From 64fd2a6858d18eb2d7c26939adfc9b59c9543bc3 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Thu, 30 May 2024 14:06:03 +0900 Subject: [PATCH] Add HLL libraries for Mamanyonyo == Handles As a general pattern, these libraries have an interface based on integer handles allocated by Open() and released by Close(); in the AliceSoft's implementation, handles are pointers to internal objects. Note that: * 0 is used to represent an invalid handle, and * Small numbers cannot be handles. For example, Mamanyonyo has code that treats an integer as a CG number if it is less than 10000, and as a surface handle otherwise. In this patch, handles are generated using id_pool.h functions. In order to achieve the above, the interface is extended so that the minimum ID value can be specified (the `base` parameter of id_pool_init()). == Graphics System Surface objects (implemented in vmSurface.[ch]) plays a central role in Mamanyonyo's graphics system, and the sprite system (vmSprite.c) is implemented on top of it. vmSprite.c uses scene.h functions. == vmChrLoader and vmMapLoader Since Mamanyonyo's character data format is the same as Widenyo's, the ChrLoader code has been refactored and used from vmChrLoader.c. On the other hand, MapLoader and vmMapLoader do not share code because the map file format is different from Widenyo. --- CMakeLists.txt | 25 ++ game_compatibility.md | 2 +- include/id_pool.h | 12 +- src/audio.c | 11 +- src/ffi.c | 50 +++ src/hll/ChrLoader.c | 252 +++++++++----- src/hll/ChrLoader.h | 35 ++ src/hll/MamanyoDemo.c | 25 ++ src/hll/MamanyoSDemo.c | 27 ++ src/hll/vmAnime.c | 151 +++++++++ src/hll/vmArray.c | 746 +++++++++++++++++++++++++++++++++++++++++ src/hll/vmCG.c | 85 +++++ src/hll/vmChrLoader.c | 89 +++++ src/hll/vmCursor.c | 43 +++ src/hll/vmDialog.c | 53 +++ src/hll/vmDrawGauge.c | 119 +++++++ src/hll/vmDrawMsg.c | 266 +++++++++++++++ src/hll/vmDrawNumber.c | 188 +++++++++++ src/hll/vmFile.c | 372 ++++++++++++++++++++ src/hll/vmGraph.c | 214 ++++++++++++ src/hll/vmGraphQuake.c | 41 +++ src/hll/vmKey.c | 133 ++++++++ src/hll/vmMapLoader.c | 231 +++++++++++++ src/hll/vmMsgLog.c | 108 ++++++ src/hll/vmMsgSkip.c | 39 +++ src/hll/vmMusic.c | 85 +++++ src/hll/vmSound.c | 86 +++++ src/hll/vmSprite.c | 628 ++++++++++++++++++++++++++++++++++ src/hll/vmString.c | 88 +++++ src/hll/vmSurface.c | 152 +++++++++ src/hll/vmSurface.h | 37 ++ src/hll/vmSystem.c | 69 ++++ src/hll/vmTimer.c | 103 ++++++ src/id_pool.c | 56 +++- src/meson.build | 25 ++ 35 files changed, 4546 insertions(+), 100 deletions(-) create mode 100644 src/hll/ChrLoader.h create mode 100644 src/hll/MamanyoDemo.c create mode 100644 src/hll/MamanyoSDemo.c create mode 100644 src/hll/vmAnime.c create mode 100644 src/hll/vmArray.c create mode 100644 src/hll/vmCG.c create mode 100644 src/hll/vmChrLoader.c create mode 100644 src/hll/vmCursor.c create mode 100644 src/hll/vmDialog.c create mode 100644 src/hll/vmDrawGauge.c create mode 100644 src/hll/vmDrawMsg.c create mode 100644 src/hll/vmDrawNumber.c create mode 100644 src/hll/vmFile.c create mode 100644 src/hll/vmGraph.c create mode 100644 src/hll/vmGraphQuake.c create mode 100644 src/hll/vmKey.c create mode 100644 src/hll/vmMapLoader.c create mode 100644 src/hll/vmMsgLog.c create mode 100644 src/hll/vmMsgSkip.c create mode 100644 src/hll/vmMusic.c create mode 100644 src/hll/vmSound.c create mode 100644 src/hll/vmSprite.c create mode 100644 src/hll/vmString.c create mode 100644 src/hll/vmSurface.c create mode 100644 src/hll/vmSurface.h create mode 100644 src/hll/vmSystem.c create mode 100644 src/hll/vmTimer.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fe202a..362b830 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,8 @@ target_sources(xsystem4 PRIVATE src/hll/LoadCG.c src/hll/MainEXFile.c src/hll/MainSurface.c + src/hll/MamanyoDemo.c + src/hll/MamanyoSDemo.c src/hll/MarmotModelEngine.c src/hll/Math.c src/hll/MapLoader.c @@ -173,6 +175,29 @@ target_sources(xsystem4 PRIVATE src/hll/SystemServiceEx.c src/hll/Timer.c src/hll/Toushin3Loader.c + src/hll/vmAnime.c + src/hll/vmArray.c + src/hll/vmCG.c + src/hll/vmChrLoader.c + src/hll/vmCursor.c + src/hll/vmDialog.c + src/hll/vmDrawGauge.c + src/hll/vmDrawMsg.c + src/hll/vmDrawNumber.c + src/hll/vmFile.c + src/hll/vmGraph.c + src/hll/vmGraphQuake.c + src/hll/vmKey.c + src/hll/vmMapLoader.c + src/hll/vmMsgLog.c + src/hll/vmMsgSkip.c + src/hll/vmMusic.c + src/hll/vmSound.c + src/hll/vmSprite.c + src/hll/vmString.c + src/hll/vmSurface.c + src/hll/vmSystem.c + src/hll/vmTimer.c src/hll/VSFile.c ) diff --git a/game_compatibility.md b/game_compatibility.md index 3475fd6..3359708 100644 --- a/game_compatibility.md +++ b/game_compatibility.md @@ -15,7 +15,7 @@ issues, please let me know or open a pull request to update this table. | Game | Status | Notes | | ------------------------------------------------------- | ----------- | ----- | | DALK外伝 | Unsupported | | -| ままにょにょ | Unsupported | | +| ままにょにょ | Supported | | | 大番長 -Big Bang Age- | Supported | | | Daibanchou -Big Bang Age- (EN) | Supported | | | 魔女の贖罪 | Unknown | | diff --git a/include/id_pool.h b/include/id_pool.h index 42a17c0..6b071ad 100644 --- a/include/id_pool.h +++ b/include/id_pool.h @@ -17,14 +17,22 @@ #ifndef SYSTEM4_ID_POOL_H #define SYSTEM4_ID_POOL_H +// A reasonable base value for pointer-based handles. +#define ID_POOL_HANDLE_BASE 0x100000 + struct id_pool { void **slots; int nr_slots; + int base; }; -void id_pool_init(struct id_pool *pool); -void id_pool_release(struct id_pool *pool, int id); +void id_pool_init(struct id_pool *pool, int base); +void id_pool_delete(struct id_pool *pool); +void *id_pool_release(struct id_pool *pool, int id); +int id_pool_count(struct id_pool *pool); int id_pool_get_unused(struct id_pool *pool); +int id_pool_get_first(struct id_pool *pool); +int id_pool_get_next(struct id_pool *pool, int id); void *id_pool_get(struct id_pool *pool, int id); void *id_pool_set(struct id_pool *pool, int id, void *data); diff --git a/src/audio.c b/src/audio.c index 3c7403b..141af88 100644 --- a/src/audio.c +++ b/src/audio.c @@ -43,8 +43,8 @@ void audio_init(void) if (audio_initialized) return; - id_pool_init(&wav); - id_pool_init(&bgm); + id_pool_init(&wav, 0); + id_pool_init(&bgm, 0); for (int i = 0; i < NR_ANONYMOUS_CHANNELS; i++) { anonymous_channels[i] = -1; @@ -56,10 +56,10 @@ void audio_init(void) void audio_reset(void) { - for (int i = 0; i < wav.nr_slots; i++) { + for (int i = id_pool_get_first(&wav); i >= 0; i = id_pool_get_next(&wav, i)) { wav_unprepare(i); } - for (int i = 0; i < bgm.nr_slots; i++) { + for (int i = id_pool_get_first(&bgm); i >= 0; i = id_pool_get_next(&bgm, i)) { bgm_unprepare(i); } for (int i = 0; i < NR_ANONYMOUS_CHANNELS; i++) { @@ -136,11 +136,10 @@ int bgm_prepare(int id, int no) { return audio_prepare(&bgm, id, ASSET_BGM, no); static int audio_unprepare(struct id_pool *pool, int id) { - struct channel *ch = id_pool_get(pool, id); + struct channel *ch = id_pool_release(pool, id); if (!ch) return 0; channel_close(ch); - id_pool_release(pool, id); return 1; } diff --git a/src/ffi.c b/src/ffi.c index ecdc220..0cea091 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -343,6 +343,8 @@ extern struct static_library lib_KiwiSoundEngine; extern struct static_library lib_LoadCG; extern struct static_library lib_MainEXFile; extern struct static_library lib_MainSurface; +extern struct static_library lib_MamanyoDemo; +extern struct static_library lib_MamanyoSDemo; extern struct static_library lib_MarmotModelEngine; extern struct static_library lib_Math; extern struct static_library lib_MapLoader; @@ -369,6 +371,29 @@ extern struct static_library lib_SystemServiceEx; extern struct static_library lib_TapirEngine; extern struct static_library lib_Timer; extern struct static_library lib_Toushin3Loader; +extern struct static_library lib_vmAnime; +extern struct static_library lib_vmArray; +extern struct static_library lib_vmCG; +extern struct static_library lib_vmChrLoader; +extern struct static_library lib_vmCursor; +extern struct static_library lib_vmDialog; +extern struct static_library lib_vmDrawGauge; +extern struct static_library lib_vmDrawMsg; +extern struct static_library lib_vmDrawNumber; +extern struct static_library lib_vmFile; +extern struct static_library lib_vmGraph; +extern struct static_library lib_vmGraphQuake; +extern struct static_library lib_vmKey; +extern struct static_library lib_vmMapLoader; +extern struct static_library lib_vmMsgLog; +extern struct static_library lib_vmMsgSkip; +extern struct static_library lib_vmMusic; +extern struct static_library lib_vmSound; +extern struct static_library lib_vmSprite; +extern struct static_library lib_vmString; +extern struct static_library lib_vmSurface; +extern struct static_library lib_vmSystem; +extern struct static_library lib_vmTimer; extern struct static_library lib_VSFile; static struct static_library *static_libraries[] = { @@ -414,6 +439,8 @@ static struct static_library *static_libraries[] = { &lib_LoadCG, &lib_MainEXFile, &lib_MainSurface, + &lib_MamanyoDemo, + &lib_MamanyoSDemo, &lib_MarmotModelEngine, &lib_Math, &lib_MapLoader, @@ -440,6 +467,29 @@ static struct static_library *static_libraries[] = { &lib_TapirEngine, &lib_Timer, &lib_Toushin3Loader, + &lib_vmAnime, + &lib_vmArray, + &lib_vmCG, + &lib_vmChrLoader, + &lib_vmCursor, + &lib_vmDialog, + &lib_vmDrawGauge, + &lib_vmDrawMsg, + &lib_vmDrawNumber, + &lib_vmFile, + &lib_vmGraph, + &lib_vmGraphQuake, + &lib_vmKey, + &lib_vmMapLoader, + &lib_vmMsgLog, + &lib_vmMsgSkip, + &lib_vmMusic, + &lib_vmSound, + &lib_vmSprite, + &lib_vmString, + &lib_vmSurface, + &lib_vmSystem, + &lib_vmTimer, &lib_VSFile, NULL }; diff --git a/src/hll/ChrLoader.c b/src/hll/ChrLoader.c index c71d7d2..0067477 100644 --- a/src/hll/ChrLoader.c +++ b/src/hll/ChrLoader.c @@ -28,10 +28,10 @@ #include "system4/little_endian.h" #include "audio.h" +#include "hll.h" #include "sact.h" #include "xsystem4.h" - -#include "hll.h" +#include "ChrLoader.h" /* * struct ChrHeader { @@ -50,7 +50,8 @@ * }; * * struct MineInfo { - * uint32_t unknown[6]; + * uint32_t id; + * uint32_t unknown[5]; * uint32_t status[24]; * char name[32]; * }; @@ -64,12 +65,14 @@ * }; * * struct EnmyInfo { - * uint32_t unknown[5]; + * uint32_t id; + * uint32_t unknown[4]; * uint32_t status[17]; * char name[32]; * }; */ +static char *chr_directory; static struct hash_table *chr_table; // Caches decrypted .chr file data static bool is_enemy(uint8_t *data) @@ -84,7 +87,7 @@ static uint8_t *chr_get(int id) return slot->value; char buf[32]; - sprintf(buf, "CHR/%d.chr", id); + snprintf(buf, sizeof(buf), "%s/%d.chr", chr_directory, id); char *path = gamedir_path(buf); size_t size; uint8_t *data = file_read(path, &size); @@ -102,106 +105,51 @@ static uint8_t *chr_get(int id) return data; } -static bool ChrLoader_Init(void) +void chr_loader_init(const char *dir) { + chr_directory = strdup(dir); chr_table = ht_create(512); - return true; } -static bool ChrLoader_LoadCG(int sprite, int x, int y, int id, int type) +bool chr_loader_exists(int id) +{ + return chr_get(id) != NULL; +} + +struct string *chr_loader_get_name(int id) { uint8_t *data = chr_get(id); if (!data) - return false; + return NULL; - struct sact_sprite *sp = sact_get_sprite(sprite); - if (!sp) - return false; - - int index = -1; - switch (type) { - case 0: // Unit - index = is_enemy(data) ? 0 : 1; - break; - case 1: // Attack - index = is_enemy(data) ? 1 : 2; - break; - case 2: // Damage - index = is_enemy(data) ? 2 : 3; - break; - case 3: // Face - index = is_enemy(data) ? -1 : 0; - break; - } - if (index < 0) - return false; - - size_t offset = LittleEndian_getDW(data, 12 + index * 4); - size_t size = LittleEndian_getDW(data, (is_enemy(data) ? 24 : 28) + index * 4); - struct cg *cg = cg_load_buffer(data + offset, size); - if (!cg) - return false; - sprite_set_cg(sp, cg); - cg_free(cg); - return true; + uint32_t offset = LittleEndian_getDW(data, 8); + offset += is_enemy(data) ? 88 : 120; + return cstr_to_string((char *)data + offset); } -static void chr_archive_free_data(struct archive_data *data) { /* no-op */ } - -static struct archive_ops chr_archive_ops = { - .free_data = chr_archive_free_data -}; - -static struct archive chr_archive = { .mmapped = false, .ops = &chr_archive_ops }; - -static bool ChrLoader_LoadWavFile(int sound_channel, int id) +struct string *chr_loader_get_string(int id, int index) { uint8_t *data = chr_get(id); - if (!data) - return false; + if (!data || is_enemy(data) || (unsigned)index >= 48) + return NULL; - size_t offset = LittleEndian_getDW(data, is_enemy(data) ? 36 : 44); - size_t size = LittleEndian_getDW(data, is_enemy(data) ? 40 : 48); - - struct archive_data *dfile = xcalloc(1, sizeof(struct archive_data)); - dfile->size = size; - dfile->data = data + offset; - dfile->no = id; - dfile->archive = &chr_archive; - - if (!wav_prepare_from_archive_data(sound_channel, dfile)) { - WARNING("ChrLoader.LoadWavFile %d failed", id); - return false; - } - return true; -} - -static bool ChrLoader_LoadSentence(int id, int type, struct string **msg) -{ - uint8_t *data = chr_get(id); - if (!data || is_enemy(data) || (unsigned)type >= 48) - return false; - - uint32_t offset = LittleEndian_getDW(data, 52 + type * 4); + uint32_t offset = LittleEndian_getDW(data, 52 + index * 4); if (!offset) - return false; - *msg = cstr_to_string((char *)data + offset); - return true; + return NULL; + return cstr_to_string((char *)data + offset); } -static bool ChrLoader_GetName(int id, struct string **name) +int chr_loader_get_id(int id) { uint8_t *data = chr_get(id); if (!data) return false; uint32_t offset = LittleEndian_getDW(data, 8); - offset += is_enemy(data) ? 88 : 120; - *name = cstr_to_string((char *)data + offset); - return true; + return LittleEndian_getDW(data, offset); } -static int ChrLoader_GetStatus(int id, int type) +int chr_loader_get_status(int id, int type) { uint8_t *data = chr_get(id); if (!data) @@ -226,9 +174,143 @@ static int ChrLoader_GetStatus(int id, int type) return LittleEndian_getDW(data, offset); } -static bool ChrLoader_IsExist(int id) +int chr_loader_get_blob_handle(int id, int index) { - return chr_get(id) != NULL; + if (!chr_get(id) || index < 0 || index > 4) + return 0; + return (id << 3) + index + 1; +} + +void *chr_loader_get_blob(int blob_handle, size_t *size) +{ + if (!blob_handle) + return NULL; + int id = blob_handle >> 3; + int index = (blob_handle & 7) - 1; + uint8_t *data = chr_get(id); + if (!data || index < 0 || index > 4) + return NULL; + + size_t ofs_ofs; + size_t size_ofs; + if (is_enemy(data)) { + if (index == 4) { + ofs_ofs = 36; + size_ofs = 40; + } else { + ofs_ofs = 12 + index * 4; + size_ofs = 24 + index * 4; + } + } else { + if (index == 4) { + ofs_ofs = 44; + size_ofs = 48; + } else { + ofs_ofs = 12 + index * 4; + size_ofs = 28 + index * 4; + } + } + size_t offset = LittleEndian_getDW(data, ofs_ofs); + *size = LittleEndian_getDW(data, size_ofs); + return data + offset; +} + +static void chr_archive_free_data(struct archive_data *data) { /* no-op */ } + +static struct archive_ops chr_archive_ops = { + .free_data = chr_archive_free_data +}; + +static struct archive chr_archive = { .mmapped = false, .ops = &chr_archive_ops }; + +struct archive_data *chr_loader_get_blob_as_archive_data(int blob_handle) +{ + size_t size; + uint8_t *data = chr_loader_get_blob(blob_handle, &size); + if (!data) + return NULL; + + struct archive_data *dfile = xcalloc(1, sizeof(struct archive_data)); + dfile->size = size; + dfile->data = data; + dfile->archive = &chr_archive; + return dfile; +} + +static bool ChrLoader_Init(void) +{ + chr_loader_init("CHR"); + return true; +} + +static bool ChrLoader_LoadCG(int sprite, int x, int y, int id, int type) +{ + struct sact_sprite *sp = sact_get_sprite(sprite); + if (!sp) + return false; + + uint8_t *data = chr_get(id); + if (!data) + return false; + + int index = -1; + switch (type) { + case 0: // Unit + index = is_enemy(data) ? 0 : 1; + break; + case 1: // Attack + index = is_enemy(data) ? 1 : 2; + break; + case 2: // Damage + index = is_enemy(data) ? 2 : 3; + break; + case 3: // Face + index = is_enemy(data) ? -1 : 0; + break; + } + if (index < 0) + return false; + + size_t size; + uint8_t *blob = chr_loader_get_blob(chr_loader_get_blob_handle(id, index), &size); + if (!blob) + return false; + + struct cg *cg = cg_load_buffer(blob, size); + if (!cg) + return false; + sprite_set_cg(sp, cg); + cg_free(cg); + return true; +} + +static bool ChrLoader_LoadWavFile(int sound_channel, int id) +{ + int blob = chr_loader_get_blob_handle(id, 4); + struct archive_data *dfile = chr_loader_get_blob_as_archive_data(blob); + if (!dfile || !wav_prepare_from_archive_data(sound_channel, dfile)) { + WARNING("ChrLoader.LoadWavFile %d failed", id); + return false; + } + return true; +} + +static bool ChrLoader_LoadSentence(int id, int type, struct string **msg) +{ + struct string *s = chr_loader_get_string(id, type); + if (!s) + return false; + *msg = s; + return true; +} + +static bool ChrLoader_GetName(int id, struct string **name) +{ + struct string *s = chr_loader_get_name(id); + if (!s) + return false; + *name = s; + return true; } HLL_LIBRARY(ChrLoader, @@ -237,6 +319,6 @@ HLL_LIBRARY(ChrLoader, HLL_EXPORT(LoadWavFile, ChrLoader_LoadWavFile), HLL_EXPORT(LoadSentence, ChrLoader_LoadSentence), HLL_EXPORT(GetName, ChrLoader_GetName), - HLL_EXPORT(GetStatus, ChrLoader_GetStatus), - HLL_EXPORT(IsExist, ChrLoader_IsExist) + HLL_EXPORT(GetStatus, chr_loader_get_status), + HLL_EXPORT(IsExist, chr_loader_exists) ); diff --git a/src/hll/ChrLoader.h b/src/hll/ChrLoader.h new file mode 100644 index 0000000..25885fb --- /dev/null +++ b/src/hll/ChrLoader.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef SYSTEM4_HLL_CHRLOADER_H +#define SYSTEM4_HLL_CHRLOADER_H + +#include + +struct archive_data; +struct string; + +void chr_loader_init(const char *dir); +bool chr_loader_exists(int id); +struct string *chr_loader_get_name(int id); +struct string *chr_loader_get_string(int id, int index); +int chr_loader_get_id(int id); +int chr_loader_get_status(int id, int type); +int chr_loader_get_blob_handle(int id, int index); +void *chr_loader_get_blob(int blob_handle, size_t *size); +struct archive_data *chr_loader_get_blob_as_archive_data(int blob_handle); + +#endif /* SYSTEM4_HLL_CHRLOADER_H */ diff --git a/src/hll/MamanyoDemo.c b/src/hll/MamanyoDemo.c new file mode 100644 index 0000000..7b76fa1 --- /dev/null +++ b/src/hll/MamanyoDemo.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "hll.h" + +HLL_WARN_UNIMPLEMENTED(1, int, MamanyoDemo, Init, void *imainsystem); +HLL_WARN_UNIMPLEMENTED(0, int, MamanyoDemo, Run, void); + +HLL_LIBRARY(MamanyoDemo, + HLL_EXPORT(Init, MamanyoDemo_Init), + HLL_EXPORT(Run, MamanyoDemo_Run) + ); diff --git a/src/hll/MamanyoSDemo.c b/src/hll/MamanyoSDemo.c new file mode 100644 index 0000000..7ea0eba --- /dev/null +++ b/src/hll/MamanyoSDemo.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "hll.h" + +HLL_WARN_UNIMPLEMENTED(0, int, MamanyoSDemo, Init, void *imainsystem); +//int MamanyoSDemo_Run(void); +//int MamanyoSDemo_AddChara(int nNum); + +HLL_LIBRARY(MamanyoSDemo, + HLL_EXPORT(Init, MamanyoSDemo_Init), + HLL_TODO_EXPORT(Run, MamanyoSDemo_Run), + HLL_TODO_EXPORT(AddChara, MamanyoSDemo_AddChara) + ); diff --git a/src/hll/vmAnime.c b/src/hll/vmAnime.c new file mode 100644 index 0000000..a4cdcdc --- /dev/null +++ b/src/hll/vmAnime.c @@ -0,0 +1,151 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "system4/cg.h" + +#include "asset_manager.h" +#include "audio.h" +#include "gfx/gfx.h" +#include "hll.h" +#include "id_pool.h" + +struct vm_anime { + int cg; + int length; + int type; + int interval; + Point pos; + int wave_channel; +}; + +static struct id_pool pool; + +static void vmAnime_New(possibly_unused void *imainsystem) +{ + if (pool.slots) + return; // already initialized + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmAnime_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmAnime_Open(int cg, int length, int type) +{ + int no = id_pool_get_unused(&pool); + struct vm_anime *anime = xcalloc(1, sizeof(struct vm_anime)); + id_pool_set(&pool, no, anime); + anime->cg = cg; + anime->length = length; + anime->type = type; + return no; +} + +static void vmAnime_Close(int handle) +{ + struct vm_anime *anime = id_pool_release(&pool, handle); + if (anime) + free(anime); +} + +static int vmAnime_Release(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmAnime_Close(i); + id_pool_delete(&pool); + return 1; +} + +static void vmAnime_ModuleFini(void) +{ + vmAnime_Release(); +} + +static void vmAnime_SetInterval(int handle, int interval) +{ + struct vm_anime *anime = id_pool_get(&pool, handle); + if (!anime) + return; + anime->interval = interval; +} + +static void vmAnime_SetPos(int handle, int x, int y) +{ + struct vm_anime *anime = id_pool_get(&pool, handle); + if (!anime) + return; + anime->pos.x = x; + anime->pos.y = y; +} + +static void vmAnime_SetWave(int handle, int channel) +{ + struct vm_anime *anime = id_pool_get(&pool, handle); + if (!anime) + return; + anime->wave_channel = channel; +} + +static void vmAnime_Draw(int handle, int return_) +{ + struct vm_anime *anime = id_pool_get(&pool, handle); + if (!anime) + return; + + if (anime->wave_channel) { + wav_stop(anime->wave_channel); + wav_play(anime->wave_channel); + } + + Texture old; + gfx_copy_main_surface(&old); + Texture *dst = gfx_main_surface(); + + uint64_t start_time = SDL_GetTicks64(); + for (int i = 0; i < anime->length; i++) { + struct cg *cg = asset_cg_load(anime->cg + i); + Texture src; + gfx_init_texture_with_cg(&src, cg); + gfx_copy(dst, 0, 0, &old, 0, 0, old.w, old.h); + gfx_blend_add_satur(dst, anime->pos.x, anime->pos.y, &src, 0, 0, src.w, src.h); + gfx_delete_texture(&src); + cg_free(cg); + gfx_swap(); + SDL_Delay(start_time + (i + 1) * anime->interval - SDL_GetTicks64()); + } + if (return_) { + gfx_copy(dst, 0, 0, &old, 0, 0, old.w, old.h); + gfx_swap(); + } + gfx_delete_texture(&old); +} + +HLL_LIBRARY(vmAnime, + HLL_EXPORT(_ModuleFini, vmAnime_ModuleFini), + HLL_EXPORT(New, vmAnime_New), + HLL_EXPORT(Release, vmAnime_Release), + HLL_EXPORT(EnumHandle, vmAnime_EnumHandle), + HLL_EXPORT(Open, vmAnime_Open), + HLL_EXPORT(Close, vmAnime_Close), + HLL_EXPORT(SetInterval, vmAnime_SetInterval), + HLL_EXPORT(SetPos, vmAnime_SetPos), + HLL_EXPORT(SetWave, vmAnime_SetWave), + HLL_EXPORT(Draw, vmAnime_Draw) + ); diff --git a/src/hll/vmArray.c b/src/hll/vmArray.c new file mode 100644 index 0000000..92aa8dc --- /dev/null +++ b/src/hll/vmArray.c @@ -0,0 +1,746 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "hll.h" +#include "vm/page.h" + +static void check_array(struct page *array) +{ + if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->array.rank != 1) + VM_ERROR("Not a flat integer array"); +} + +//int vmArray_GetAdd(struct page *array, int index); +//int vmArray_GetSub(struct page *array, int index); +//int vmArray_GetMul(struct page *array, int index); +//int vmArray_GetDiv(struct page *array, int index); +//int vmArray_GetAnd(struct page *array, int index); +//int vmArray_GetOr(struct page *array, int index); +//int vmArray_GetXor(struct page *array, int index); + +static void transform(struct page *array, int index, int (*func)(int, void *), void *data) +{ + if (!array) + return; + check_array(array); + + if (index >= 0) { + for (int i = index; i < array->nr_vars; i++) { + array->values[i].i = func(array->values[i].i, data); + } + } else { + for (int i = -index - 1; i >= 0; --i) { + array->values[i].i = func(array->values[i].i, data); + } + } +} + +static inline int32_t clamp(int64_t val) +{ + if (val > INT32_MAX) + return INT32_MAX; + if (val < INT32_MIN) + return INT32_MIN; + return val; +} + +static int trans_add(int x, void *data) +{ + int64_t y = *(int*)data; + return clamp(x + y); +} + +static int trans_sub(int x, void *data) +{ + int64_t y = *(int*)data; + return clamp(x - y); +} + +static int trans_mul(int x, void *data) +{ + int64_t y = *(int*)data; + return clamp(x * y); +} + +static int trans_div(int x, void *data) +{ + int64_t y = *(int*)data; + return clamp(x / y); +} + +static int trans_and(int x, void *data) +{ + int y = *(int*)data; + return x & y; +} + +static int trans_or(int x, void *data) +{ + int y = *(int*)data; + return x | y; +} + +static int trans_xor(int x, void *data) +{ + int y = *(int*)data; + return x ^ y; +} + +static void vmArray_AddNum(struct page **array, int index, int num) +{ + transform(*array, index, trans_add, &num); +} + +static void vmArray_SubNum(struct page **array, int index, int num) +{ + transform(*array, index, trans_sub, &num); +} + +static void vmArray_MulNum(struct page **array, int index, int num) +{ + transform(*array, index, trans_mul, &num); +} + +static void vmArray_DivNum(struct page **array, int index, int num) +{ + if (num != 0) + transform(*array, index, trans_div, &num); +} + +static void vmArray_AndNum(struct page **array, int index, int num) +{ + transform(*array, index, trans_and, &num); +} + +static void vmArray_OrNum(struct page **array, int index, int num) +{ + transform(*array, index, trans_or, &num); +} + +static void vmArray_XorNum(struct page **array, int index, int num) +{ + transform(*array, index, trans_xor, &num); +} + +//void vmArray_MinNum(struct page **array, int index, int num); +//void vmArray_MaxNum(struct page **array, int index, int num); + +struct vmarray_iter { + struct page *array; + int index; +}; + +static int trans_add_array(int x, void *data) +{ + struct vmarray_iter *iter = data; + return clamp((int64_t)x + iter->array->values[iter->index++].i); +} + +static int trans_sub_array(int x, void *data) +{ + struct vmarray_iter *iter = data; + return clamp((int64_t)x - iter->array->values[iter->index++].i); +} + +static int trans_mul_array(int x, void *data) +{ + struct vmarray_iter *iter = data; + return clamp((int64_t)x * iter->array->values[iter->index++].i); +} + +static int trans_div_array(int x, void *data) +{ + struct vmarray_iter *iter = data; + int rhs = iter->array->values[iter->index++].i; + return rhs ? x / rhs : x; +} + +static int trans_and_array(int x, void *data) +{ + struct vmarray_iter *iter = data; + return x & iter->array->values[iter->index++].i; +} + +static int trans_or_array(int x, void *data) +{ + struct vmarray_iter *iter = data; + return x | iter->array->values[iter->index++].i; +} + +static int trans_xor_array(int x, void *data) +{ + struct vmarray_iter *iter = data; + return x ^ iter->array->values[iter->index++].i; +} + +static void vmArray_AddArray(struct page **d_array, int index, struct page *s_array) +{ + struct vmarray_iter iter = { s_array, 0 }; + transform(*d_array, index, trans_add_array, &iter); +} + +static void vmArray_SubArray(struct page **d_array, int index, struct page *s_array) +{ + struct vmarray_iter iter = { s_array, 0 }; + transform(*d_array, index, trans_sub_array, &iter); +} + +static void vmArray_MulArray(struct page **d_array, int index, struct page *s_array) +{ + struct vmarray_iter iter = { s_array, 0 }; + transform(*d_array, index, trans_mul_array, &iter); +} + +static void vmArray_DivArray(struct page **d_array, int index, struct page *s_array) +{ + struct vmarray_iter iter = { s_array, 0 }; + transform(*d_array, index, trans_div_array, &iter); +} + +static void vmArray_AndArray(struct page **d_array, int index, struct page *s_array) +{ + struct vmarray_iter iter = { s_array, 0 }; + transform(*d_array, index, trans_and_array, &iter); +} + +static void vmArray_OrArray(struct page **d_array, int index, struct page *s_array) +{ + struct vmarray_iter iter = { s_array, 0 }; + transform(*d_array, index, trans_or_array, &iter); +} + +static void vmArray_XorArray(struct page **d_array, int index, struct page *s_array) +{ + struct vmarray_iter iter = { s_array, 0 }; + transform(*d_array, index, trans_xor_array, &iter); +} + +//void vmArray_MinArray(struct page **d_array, int index, struct page *s_array); +//void vmArray_MaxArray(struct page **d_array, int index, struct page *s_array); + +static bool pred_equal(int x, void *data) +{ + int y = *(int*)data; + return x == y; +} + +static bool pred_not_equal(int x, void *data) +{ + int y = *(int*)data; + return x != y; +} + +static bool pred_low(int x, void *data) +{ + int y = *(int*)data; + return x <= y; +} + +static bool pred_high(int x, void *data) +{ + int y = *(int*)data; + return y <= x; +} + +struct range { + int min; + int max; +}; + +static bool pred_in_range(int x, void *data) +{ + struct range *r = data; + return r->min <= x && x <= r->max; +} + +static int count_if(struct page *array, int index, bool (*pred)(int, void *), void *data) +{ + if (!array) + return 0; + check_array(array); + + int count = 0; + for (int i = index; i < array->nr_vars; i++) { + if (pred(array->values[i].i, data)) + count++; + } + return count; +} + +static int vmArray_EnumEquNum(struct page *array, int index, int num) +{ + return count_if(array, index, pred_equal, &num); +} + +static int vmArray_EnumNotNum(struct page *array, int index, int num) +{ + return count_if(array, index, pred_not_equal, &num); +} + +static int vmArray_EnumLowNum(struct page *array, int index, int num) +{ + return count_if(array, index, pred_low, &num); +} + +static int vmArray_EnumHighNum(struct page *array, int index, int num) +{ + return count_if(array, index, pred_high, &num); +} + +static int vmArray_EnumRangeNum(struct page *array, int index, int min, int max) +{ + struct range r = { .min = min, .max = max }; + return count_if(array, index, pred_in_range, &r); +} + +static void replace(struct page *array, int index, int n, bool (*pred)(int, void *), void *data) +{ + if (!array) + return; + check_array(array); + + for (int i = index; i < array->nr_vars; i++) { + if (pred(array->values[i].i, data)) + array->values[i].i = n; + } +} + +static void vmArray_ChangeEquNum(struct page **array, int index, int num, int exg) +{ + replace(*array, index, exg, pred_equal, &num); +} + +static void vmArray_ChangeNotNum(struct page **array, int index, int num, int exg) +{ + replace(*array, index, exg, pred_not_equal, &num); +} + +static void vmArray_ChangeLowNum(struct page **array, int index, int num, int exg) +{ + replace(*array, index, exg, pred_low, &num); +} + +static void vmArray_ChangeHighNum(struct page **array, int index, int num, int exg) +{ + replace(*array, index, exg, pred_high, &num); +} + +static void vmArray_ChangeRangeNum(struct page **array, int index, int min, int max, int exg) +{ + struct range r = { .min = min, .max = max }; + replace(*array, index, exg, pred_in_range, &r); +} + +static int find(struct page *array, int index, bool (*pred)(int, void *), void *data, int *out_index) +{ + if (!array) + return 0; + check_array(array); + + if (index >= 0) { + for (int i = index; i < array->nr_vars; i++) { + if (pred(array->values[i].i, data)) { + *out_index = i; + return 1; + } + } + } else { + for (int i = -index - 1; i >= 0; --i) { + if (pred(array->values[i].i, data)) { + *out_index = i; + return 1; + } + } + } + return 0; +} + +static int vmArray_GrepEquNum(struct page *array, int index, int num, int *out_index) +{ + return find(array, index, pred_equal, &num, out_index); +} + +static int vmArray_GrepNotNum(struct page *array, int index, int num, int *out_index) +{ + return find(array, index, pred_not_equal, &num, out_index); +} + +static int vmArray_GrepLowNum(struct page *array, int index, int num, int *out_index) +{ + return find(array, index, pred_low, &num, out_index); +} + +static int vmArray_GrepHighNum(struct page *array, int index, int num, int *out_index) +{ + return find(array, index, pred_high, &num, out_index); +} + +static int vmArray_GrepRangeNum(struct page *array, int index, int min, int max, int *out_index) +{ + struct range r = { .min = min, .max = max }; + return find(array, index, pred_in_range, &r, out_index); +} + +static int vmArray_GrepLowOrder(struct page *s_array, int index, struct page **d_array_, int *out_index) +{ + struct page *d_array = *d_array_; + check_array(s_array); + check_array(d_array); + + if (index < 0) + VM_ERROR("not implemented"); + + int min_index = -1, min_value; + for (int i = index; i < s_array->nr_vars; i++) { + if (d_array->values[i].i) + continue; + int val = s_array->values[i].i; + if (min_index < 0 || val < min_value) { + min_index = i; + min_value = val; + } + } + if (min_index < 0) + return 0; + *out_index = min_index; + d_array->values[min_index].i = 1; + return 1; +} + +static int vmArray_GrepHighOrder(struct page *s_array, int index, struct page **d_array_, int *out_index) +{ + struct page *d_array = *d_array_; + check_array(s_array); + check_array(d_array); + + if (index < 0) + VM_ERROR("not implemented"); + + int max_index = -1, max_value; + for (int i = index; i < s_array->nr_vars; i++) { + if (d_array->values[i].i) + continue; + int val = s_array->values[i].i; + if (max_index < 0 || val > max_value) { + max_index = i; + max_value = val; + } + } + if (max_index < 0) + return 0; + *out_index = max_index; + d_array->values[max_index].i = 1; + return 1; +} + +static void map_predicate(struct page *s_array, int index, bool (*pred)(int, void *), void *data, struct page *d_array) +{ + if (!s_array || !d_array) + return; + check_array(s_array); + check_array(d_array); + + if (index >= 0) { + for (int i = index; i < s_array->nr_vars; i++) { + d_array->values[i].i = pred(s_array->values[i].i, data) ? 1 : 0; + } + } else { + for (int i = -index - 1; i >= 0; --i) { + d_array->values[i].i = pred(s_array->values[i].i, data) ? 1 : 0; + } + } +} + +static void vmArray_SetEquNum(struct page *s_array, int index, int num, struct page **d_array) +{ + map_predicate(s_array, index, pred_equal, &num, *d_array); +} + +static void vmArray_SetNotNum(struct page *s_array, int index, int num, struct page **d_array) +{ + map_predicate(s_array, index, pred_not_equal, &num, *d_array); +} + +static void vmArray_SetLowNum(struct page *s_array, int index, int num, struct page **d_array) +{ + map_predicate(s_array, index, pred_low, &num, *d_array); +} + +static void vmArray_SetHighNum(struct page *s_array, int index, int num, struct page **d_array) +{ + map_predicate(s_array, index, pred_high, &num, *d_array); +} + +static void vmArray_SetRangeNum(struct page *s_array, int index, int min, int max, struct page **d_array) +{ + struct range r = { .min = min, .max = max }; + map_predicate(s_array, index, pred_in_range, &r, *d_array); +} + +//void vmArray_AndEquNum(struct page *pISVMArray, int index, int num, struct page **pIDVMArray); +//void vmArray_AndNotNum(struct page *pISVMArray, int index, int num, struct page **pIDVMArray); +//void vmArray_AndLowNum(struct page *pISVMArray, int index, int num, struct page **pIDVMArray); +//void vmArray_AndHighNum(struct page *pISVMArray, int index, int num, struct page **pIDVMArray); +//void vmArray_AndRangeNum(struct page *pISVMArray, int index, int nMin, int nMax, struct page **pIDVMArray); + +static void set_if(struct page *s_array, int index, bool (*pred)(int, void *), void *data, struct page *d_array) +{ + if (!s_array || !d_array) + return; + check_array(s_array); + check_array(d_array); + + if (index >= 0) { + for (int i = index; i < s_array->nr_vars; i++) { + if (pred(s_array->values[i].i, data)) + d_array->values[i].i = 1; + } + } else { + for (int i = -index - 1; i >= 0; --i) { + if (pred(s_array->values[i].i, data)) + d_array->values[i].i = 1; + } + } +} + +static void vmArray_OrEquNum(struct page *s_array, int index, int num, struct page **d_array) +{ + set_if(s_array, index, pred_equal, &num, *d_array); +} + +static void vmArray_OrNotNum(struct page *s_array, int index, int num, struct page **d_array) +{ + set_if(s_array, index, pred_not_equal, &num, *d_array); +} + +static void vmArray_OrLowNum(struct page *s_array, int index, int num, struct page **d_array) +{ + set_if(s_array, index, pred_low, &num, *d_array); +} + +static void vmArray_OrHighNum(struct page *s_array, int index, int num, struct page **d_array) +{ + set_if(s_array, index, pred_high, &num, *d_array); +} + +static void vmArray_OrRangeNum(struct page *s_array, int index, int min, int max, struct page **d_array) +{ + struct range r = { .min = min, .max = max }; + set_if(s_array, index, pred_in_range, &r, *d_array); +} + +// Find num by visiting elements spirally around (x, y). +static int vmArray_AroundRect(struct page *array, int width, int height, int x, int y, int length, int num, int *out_x, int *out_y) +{ + for (int dist = 1;; dist++) { + if (--length < 0) + return 0; + y--; + if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num) + goto found; + + for (int i = 0; i < dist; i++) { + if (--length < 0) + return 0; + x++; + y++; + if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num) + goto found; + } + for (int i = 0; i < dist; i++) { + if (--length < 0) + return 0; + x--; + y++; + if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num) + goto found; + } + for (int i = 0; i < dist; i++) { + if (--length < 0) + return 0; + x--; + y--; + if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num) + goto found; + } + for (int i = 0; i < dist; i++) { + if (--length < 0) + return 0; + x++; + y--; + if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num) + goto found; + } + } + found: + *out_x = x; + *out_y = y; + return 1; +} + +//int vmArray_AroundHexa(struct page *array, int nWidth, int nHeight, int nX, int nY, int nLength, int num, int *pnRX, int *pnRY); + +static int vmArray_PaintRect(struct page **array_, int width, int height, int x, int y, int length) +{ + struct page *array = *array_; + check_array(array); + if (array->nr_vars < width * height || x >= width || y >= height || length < 0) + return 0; + + int size = width * height; + for (int i = 0; i < size; i++) { + array->values[i].i = array->values[i].i < 0 ? -2 : -1; + } + + int count = 0; + array->values[y * width + x].i = 0; + for (int dist = 0; dist < length; dist++) { + for (int i = 0; i < size; i++) { + if (array->values[i].i != dist) + continue; + if (i / width > 0 && array->values[i - width].i == -1) { + array->values[i - width].i = dist + 1; + count++; + } + if (i / width < height - 1 && array->values[i + width].i == -1) { + array->values[i + width].i = dist + 1; + count++; + } + if (i % width > 0 && array->values[i - 1].i == -1) { + array->values[i - 1].i = dist + 1; + count++; + } + if (i % width < width - 1 && array->values[i + 1].i == -1) { + array->values[i + 1].i = dist + 1; + count++; + } + } + } + return count; +} + +//int vmArray_PaintHexa(struct page **pIVMArray, int nWidth, int nHeight, int nX, int nY, int nLength); + +static int vmArray_CopyRectToRect(struct page **d_array_, int dw, int dh, int dx, int dy, struct page *s_array, int sw, int sh, int sx, int sy, int w, int h) +{ + struct page *d_array = *d_array_; + check_array(s_array); + check_array(d_array); + if (s_array->nr_vars < sw * sh || d_array->nr_vars < dw * dh) + return 0; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + if (dx + x < 0 || dx + x >= dw || dy + y < 0 || dy + y >= dh) + continue; + if (sx + x < 0 || sx + x >= sw || sy + y < 0 || sy + y >= sh) + continue; + d_array->values[(dy + y) * dw + dx + x] = s_array->values[(sy + y) * sw + sx + x]; + } + } + return 1; +} + +//int vmArray_CopyHexaToHexa(struct page **pIDVMArray, int nDWidth, int nDHeight, int nDx, int nDy, struct page *pISVMArray, int nSWidth, int nSHeight, int nSx, int nSy, int nCWidth, int nCHeight); + +// Transpose s_array (as a 2D array of s_width * s_height) into d_array. +static int vmArray_ConvertRectSide(struct page **d_array_, struct page *s_array, int s_width, int s_height, int side) +{ + struct page *d_array = *d_array_; + check_array(s_array); + check_array(d_array); + int w = side ? s_width : s_height; + int h = side ? s_height : s_width; + + if (s_array->nr_vars < w * h || d_array->nr_vars < w * h) + return 0; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + d_array->values[x * h + y] = s_array->values[y * w + x]; + } + } + return 1; +} + +HLL_LIBRARY(vmArray, + HLL_TODO_EXPORT(GetAdd, vmArray_GetAdd), + HLL_TODO_EXPORT(GetSub, vmArray_GetSub), + HLL_TODO_EXPORT(GetMul, vmArray_GetMul), + HLL_TODO_EXPORT(GetDiv, vmArray_GetDiv), + HLL_TODO_EXPORT(GetAnd, vmArray_GetAnd), + HLL_TODO_EXPORT(GetOr, vmArray_GetOr), + HLL_TODO_EXPORT(GetXor, vmArray_GetXor), + HLL_EXPORT(AddNum, vmArray_AddNum), + HLL_EXPORT(SubNum, vmArray_SubNum), + HLL_EXPORT(MulNum, vmArray_MulNum), + HLL_EXPORT(DivNum, vmArray_DivNum), + HLL_EXPORT(AndNum, vmArray_AndNum), + HLL_EXPORT(OrNum, vmArray_OrNum), + HLL_EXPORT(XorNum, vmArray_XorNum), + HLL_TODO_EXPORT(MinNum, vmArray_MinNum), + HLL_TODO_EXPORT(MaxNum, vmArray_MaxNum), + HLL_EXPORT(AddArray, vmArray_AddArray), + HLL_EXPORT(SubArray, vmArray_SubArray), + HLL_EXPORT(MulArray, vmArray_MulArray), + HLL_EXPORT(DivArray, vmArray_DivArray), + HLL_EXPORT(AndArray, vmArray_AndArray), + HLL_EXPORT(OrArray, vmArray_OrArray), + HLL_EXPORT(XorArray, vmArray_XorArray), + HLL_TODO_EXPORT(MinArray, vmArray_MinArray), + HLL_TODO_EXPORT(MaxArray, vmArray_MaxArray), + HLL_EXPORT(EnumEquNum, vmArray_EnumEquNum), + HLL_EXPORT(EnumNotNum, vmArray_EnumNotNum), + HLL_EXPORT(EnumLowNum, vmArray_EnumLowNum), + HLL_EXPORT(EnumHighNum, vmArray_EnumHighNum), + HLL_EXPORT(EnumRangeNum, vmArray_EnumRangeNum), + HLL_EXPORT(ChangeEquNum, vmArray_ChangeEquNum), + HLL_EXPORT(ChangeNotNum, vmArray_ChangeNotNum), + HLL_EXPORT(ChangeLowNum, vmArray_ChangeLowNum), + HLL_EXPORT(ChangeHighNum, vmArray_ChangeHighNum), + HLL_EXPORT(ChangeRangeNum, vmArray_ChangeRangeNum), + HLL_EXPORT(GrepEquNum, vmArray_GrepEquNum), + HLL_EXPORT(GrepNotNum, vmArray_GrepNotNum), + HLL_EXPORT(GrepLowNum, vmArray_GrepLowNum), + HLL_EXPORT(GrepHighNum, vmArray_GrepHighNum), + HLL_EXPORT(GrepRangeNum, vmArray_GrepRangeNum), + HLL_EXPORT(GrepLowOrder, vmArray_GrepLowOrder), + HLL_EXPORT(GrepHighOrder, vmArray_GrepHighOrder), + HLL_EXPORT(SetEquNum, vmArray_SetEquNum), + HLL_EXPORT(SetNotNum, vmArray_SetNotNum), + HLL_EXPORT(SetLowNum, vmArray_SetLowNum), + HLL_EXPORT(SetHighNum, vmArray_SetHighNum), + HLL_EXPORT(SetRangeNum, vmArray_SetRangeNum), + HLL_TODO_EXPORT(AndEquNum, vmArray_AndEquNum), + HLL_TODO_EXPORT(AndNotNum, vmArray_AndNotNum), + HLL_TODO_EXPORT(AndLowNum, vmArray_AndLowNum), + HLL_TODO_EXPORT(AndHighNum, vmArray_AndHighNum), + HLL_TODO_EXPORT(AndRangeNum, vmArray_AndRangeNum), + HLL_EXPORT(OrEquNum, vmArray_OrEquNum), + HLL_EXPORT(OrNotNum, vmArray_OrNotNum), + HLL_EXPORT(OrLowNum, vmArray_OrLowNum), + HLL_EXPORT(OrHighNum, vmArray_OrHighNum), + HLL_EXPORT(OrRangeNum, vmArray_OrRangeNum), + HLL_EXPORT(AroundRect, vmArray_AroundRect), + HLL_TODO_EXPORT(AroundHexa, vmArray_AroundHexa), + HLL_EXPORT(PaintRect, vmArray_PaintRect), + HLL_TODO_EXPORT(PaintHexa, vmArray_PaintHexa), + HLL_EXPORT(CopyRectToRect, vmArray_CopyRectToRect), + HLL_TODO_EXPORT(CopyHexaToHexa, vmArray_CopyHexaToHexa), + HLL_EXPORT(ConvertRectSide, vmArray_ConvertRectSide) + ); diff --git a/src/hll/vmCG.c b/src/hll/vmCG.c new file mode 100644 index 0000000..6e6baae --- /dev/null +++ b/src/hll/vmCG.c @@ -0,0 +1,85 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "system4.h" +#include "system4/cg.h" + +#include "asset_manager.h" +#include "gfx/gfx.h" +#include "hll.h" +#include "vmSurface.h" + +HLL_QUIET_UNIMPLEMENTED( , void, vmCG, New, void); +//int vmCG_Release(void); +HLL_WARN_UNIMPLEMENTED( , void, vmCG, SetType, int type); +//int vmCG_EnumHandle(void); + +static int vmCG_Exist(int num) +{ + return asset_exists(ASSET_CG, num); +} + +static int vmCG_Load(int num) +{ + struct cg *cg = asset_cg_load(num); + if (!cg) + return 0; + struct vm_surface *sf = vm_surface_create(cg->metrics.w, cg->metrics.h); + gfx_init_texture_with_cg(&sf->texture, cg); + sf->has_pixel = cg->metrics.has_pixel; + sf->has_alpha = cg->metrics.has_alpha; + sf->cg_no = num; + cg_free(cg); + return sf->no; +} + +static void vmCG_Unload(int surface) +{ + vm_surface_delete(surface); +} + +static int vmCG_Trans(int surface, int x, int y, int num) +{ + struct vm_surface *sf = vm_surface_get(surface); + if (!sf) + return 0; + + struct cg *cg = asset_cg_load(num); + if (!cg) + return 0; + + Texture src; + gfx_init_texture_with_cg(&src, cg); + cg_free(cg); + + if (sf->has_alpha) + gfx_copy_with_alpha_map(&sf->texture, x, y, &src, 0, 0, src.w, src.h); + else + gfx_blend_amap(&sf->texture, x, y, &src, 0, 0, src.w, src.h); + gfx_delete_texture(&src); + return 1; +} + +HLL_LIBRARY(vmCG, + HLL_EXPORT(New, vmCG_New), + HLL_TODO_EXPORT(Release, vmCG_Release), + HLL_EXPORT(SetType, vmCG_SetType), + HLL_TODO_EXPORT(EnumHandle, vmCG_EnumHandle), + HLL_EXPORT(Exist, vmCG_Exist), + HLL_EXPORT(Load, vmCG_Load), + HLL_EXPORT(Unload, vmCG_Unload), + HLL_EXPORT(Trans, vmCG_Trans) + ); diff --git a/src/hll/vmChrLoader.c b/src/hll/vmChrLoader.c new file mode 100644 index 0000000..a795ccf --- /dev/null +++ b/src/hll/vmChrLoader.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +#include "system4.h" +#include "system4/cg.h" +#include "system4/string.h" + +#include "gfx/gfx.h" +#include "hll.h" +#include "ChrLoader.h" +#include "vmSurface.h" +#include "xsystem4.h" + +static void vmChrLoader_Init(possibly_unused void *imainsystem, possibly_unused struct string *string) +{ + chr_loader_init("Chr"); +} + +static int vmChrLoader_Exist(int id) +{ + return chr_loader_exists(id) ? 1 : 0; +} + +HLL_QUIET_UNIMPLEMENTED(, void, vmChrLoader, ReleaseMemory, int id, int index); + +static struct string *vmChrLoader_GetMsg(int id, int index) +{ + struct string *msg = chr_loader_get_string(id, index); + return msg ? msg : string_ref(&EMPTY_STRING); +} + +static struct string *vmChrLoader_GetName(int id) +{ + struct string *name = chr_loader_get_name(id); + return name ? name : string_ref(&EMPTY_STRING); +} + +static int vmChrLoader_MemoryToSurface(int memory, int x, int y, int surface) +{ + struct vm_surface *sf = vm_surface_get(surface); + if (!sf) + return 0; + + size_t size; + void *data = chr_loader_get_blob(memory, &size); + if (!data) + return 0; + + struct cg *cg = cg_load_buffer(data, size); + if (!cg) + return 0; + + Texture tex; + gfx_init_texture_with_cg(&tex, cg); + cg_free(cg); + + gfx_copy(&sf->texture, x, y, &tex, 0, 0, tex.w, tex.h); + gfx_delete_texture(&tex); + return 1; +} + +HLL_LIBRARY(vmChrLoader, + HLL_EXPORT(Init, vmChrLoader_Init), + HLL_EXPORT(Exist, vmChrLoader_Exist), + HLL_EXPORT(GetID, chr_loader_get_id), + HLL_EXPORT(GetStatus, chr_loader_get_status), + HLL_EXPORT(GetMemory, chr_loader_get_blob_handle), + HLL_EXPORT(ReleaseMemory, vmChrLoader_ReleaseMemory), + HLL_EXPORT(GetMsg, vmChrLoader_GetMsg), + HLL_EXPORT(GetName, vmChrLoader_GetName), + HLL_EXPORT(MemoryToSurface, vmChrLoader_MemoryToSurface) + ); diff --git a/src/hll/vmCursor.c b/src/hll/vmCursor.c new file mode 100644 index 0000000..08845a7 --- /dev/null +++ b/src/hll/vmCursor.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "hll.h" +#include "input.h" + +HLL_QUIET_UNIMPLEMENTED( , void, vmCursor, Init, void *imainsystem); + +static void vmCursor_SetPos(int x, int y) +{ + mouse_set_pos(x, y); +} + +static int vmCursor_GetPos(int *x, int *y) +{ + handle_events(); + mouse_get_pos(x, y); + return mouse_focus && keyboard_focus; +} + +//void vmCursor_SetShow(int nShow); +//int vmCursor_GetShow(void); + +HLL_LIBRARY(vmCursor, + HLL_EXPORT(Init, vmCursor_Init), + HLL_EXPORT(SetPos, vmCursor_SetPos), + HLL_EXPORT(GetPos, vmCursor_GetPos), + HLL_TODO_EXPORT(SetShow, vmCursor_SetShow), + HLL_TODO_EXPORT(GetShow, vmCursor_GetShow) + ); diff --git a/src/hll/vmDialog.c b/src/hll/vmDialog.c new file mode 100644 index 0000000..0e63c68 --- /dev/null +++ b/src/hll/vmDialog.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "system4/string.h" +#include "system4/utfsjis.h" + +#include "hll.h" + +HLL_QUIET_UNIMPLEMENTED( , void, vmDialog, Init, void *imainsystem); + +static int vmDialog_MsgBox(struct string *t_string, struct string *string, int type, possibly_unused int default_button) +{ + uint32_t flags = (type == 4) ? SDL_MESSAGEBOX_ERROR : 0; + char *title = sjis2utf(t_string->text, 0); + char *message = sjis2utf(string->text, 0); + SDL_ShowSimpleMessageBox(flags, title, message, NULL); + free(message); + free(title); + return 1; +} + +//int vmDialog_InputNum(struct string *pITString, int nMin, int nMax, int *pnNum); +//int vmDialog_InputString(struct string *pITString, int nLength, struct string **pIString); +//int vmDialog_SelectNum(struct string *pITString, int nMin, int nMax, int *pnNum); +//int vmDialog_SelectString(struct string *pITString, struct page **pIVMArray, int nNum, struct string **pIString); +//int vmDialog_InputOpenFile(struct string *pITString, struct string **pIPString, struct string **pIString, struct string *pIDString, struct string *pIFString); +//int vmDialog_InputSaveFile(struct string *pITString, struct string **pIPString, struct string **pIString, struct string *pIDString, struct string *pIFString); + +HLL_LIBRARY(vmDialog, + HLL_EXPORT(Init, vmDialog_Init), + HLL_EXPORT(MsgBox, vmDialog_MsgBox), + HLL_TODO_EXPORT(InputNum, vmDialog_InputNum), + HLL_TODO_EXPORT(InputString, vmDialog_InputString), + HLL_TODO_EXPORT(SelectNum, vmDialog_SelectNum), + HLL_TODO_EXPORT(SelectString, vmDialog_SelectString), + HLL_TODO_EXPORT(InputOpenFile, vmDialog_InputOpenFile), + HLL_TODO_EXPORT(InputSaveFile, vmDialog_InputSaveFile) + ); diff --git a/src/hll/vmDrawGauge.c b/src/hll/vmDrawGauge.c new file mode 100644 index 0000000..2635ed6 --- /dev/null +++ b/src/hll/vmDrawGauge.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "system4/cg.h" + +#include "asset_manager.h" +#include "gfx/gfx.h" +#include "hll.h" +#include "id_pool.h" +#include "vmSurface.h" + +struct vm_drawgauge { + struct texture tex; + int surface; +}; + +static struct id_pool pool; + +static void vmDrawGauge_New(void) +{ + if (pool.slots) + return; // already initialized + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmDrawGauge_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmDrawGauge_Open(int cg_no, int origin, int phase) +{ + struct cg *cg = asset_cg_load(cg_no); + if (!cg) + return 0; + + int w = cg->metrics.w; + int h = cg->metrics.h; + + int handle = id_pool_get_unused(&pool); + struct vm_drawgauge *dg = xcalloc(1, sizeof(struct vm_drawgauge)); + id_pool_set(&pool, handle, dg); + + gfx_init_texture_with_cg(&dg->tex, cg); + cg_free(cg); + + struct vm_surface *sf = vm_surface_create(w, h); + gfx_init_texture_blank(&sf->texture, w, h); + dg->surface = sf->no; + + return handle; +} + +static void vmDrawGauge_Close(int handle) +{ + struct vm_drawgauge *dg = id_pool_release(&pool, handle); + if (!dg) + return; + gfx_delete_texture(&dg->tex); + vm_surface_delete(dg->surface); + free(dg); +} + +static int vmDrawGauge_Release(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmDrawGauge_Close(i); + id_pool_delete(&pool); + return 1; +} + +static void vmDrawGauge_ModuleFini(void) +{ + vmDrawGauge_Release(); +} + +static int vmDrawGauge_GetSurface(int handle) +{ + struct vm_drawgauge *dg = id_pool_get(&pool, handle); + return dg ? dg->surface : 0; +} + +static void vmDrawGauge_Draw(int handle, int now, int max) +{ + struct vm_drawgauge *dg = id_pool_get(&pool, handle); + if (!dg) + return; + struct vm_surface *sf = vm_surface_get(dg->surface); + if (!sf) + return; + + gfx_fill_with_alpha(&sf->texture, 0, 0, sf->texture.w, sf->texture.h, 255, 0, 255, 0); + int w = sf->texture.w * now / max; + gfx_copy_with_alpha_map(&sf->texture, 0, 0, &dg->tex, 0, 0, w, sf->texture.h); +} + +HLL_LIBRARY(vmDrawGauge, + HLL_EXPORT(_ModuleFini, vmDrawGauge_ModuleFini), + HLL_EXPORT(New, vmDrawGauge_New), + HLL_EXPORT(Release, vmDrawGauge_Release), + HLL_EXPORT(EnumHandle, vmDrawGauge_EnumHandle), + HLL_EXPORT(Open, vmDrawGauge_Open), + HLL_EXPORT(Close, vmDrawGauge_Close), + HLL_EXPORT(GetSurface, vmDrawGauge_GetSurface), + HLL_EXPORT(Draw, vmDrawGauge_Draw) + ); diff --git a/src/hll/vmDrawMsg.c b/src/hll/vmDrawMsg.c new file mode 100644 index 0000000..e03922a --- /dev/null +++ b/src/hll/vmDrawMsg.c @@ -0,0 +1,266 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "system4.h" +#include "system4/string.h" + +#include "gfx/font.h" +#include "hll.h" +#include "id_pool.h" +#include "vmSurface.h" +#include "xsystem4.h" + +enum { + SURFACE_DROP_SHADOW, + SURFACE_BOLD, + SURFACE_TEXT, + NR_SURFACES +}; + +struct style { + struct text_style ts; + int drop_shadow; + SDL_Color drop_shadow_color; + int bold; + SDL_Color bold_color; +}; + +struct vm_drawmsg { + int w; + int h; + int surfaces[NR_SURFACES]; + struct string *text; + Point pos; + Point initial_pos; + struct style style; + struct style initial_style; +}; + +static struct id_pool pool; + +static void vmDrawMsg_New(possibly_unused void *imainsystem) +{ + if (pool.slots) + return; // already initialized + gfx_font_init(); + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmDrawMsg_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmDrawMsg_Open(int width, int height) +{ + int no = id_pool_get_unused(&pool); + struct vm_drawmsg *dm = xcalloc(1, sizeof(struct vm_drawmsg)); + id_pool_set(&pool, no, dm); + dm->w = width; + dm->h = height; + for (int i = 0; i < NR_SURFACES; i++) { + struct vm_surface *sf = vm_surface_create(width, height); + dm->surfaces[i] = sf->no; + gfx_init_texture_rgba(&sf->texture, sf->w, sf->h, COLOR(0, 0, 0, 0)); + } + dm->text = string_dup(&EMPTY_STRING); + + dm->initial_style.ts.face = FONT_GOTHIC; + dm->initial_style.ts.size = 24.0f; + dm->initial_style.ts.weight = FW_BOLD; + dm->initial_style.ts.color = COLOR(255, 255, 255, 255); + dm->initial_style.ts.scale_x = 1.0; + dm->initial_style.ts.space_scale_x = 1.0f; + dm->style = dm->initial_style; + + return no; +} + +static void vmDrawMsg_Close(int handle) +{ + struct vm_drawmsg *dm = id_pool_release(&pool, handle); + if (!dm) + return; + free_string(dm->text); + for (int i = 0; i < NR_SURFACES; i++) { + vm_surface_delete(dm->surfaces[i]); + } + free(dm); +} + +static int vmDrawMsg_Release(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmDrawMsg_Close(i); + id_pool_delete(&pool); + return 1; +} + +static void vmDrawMsg_ModuleFini(void) +{ + vmDrawMsg_Release(); +} + +static int vmDrawMsg_GetNumofSurface(int handle) +{ + struct vm_drawmsg *dm = id_pool_get(&pool, handle); + return dm ? NR_SURFACES : 0; +} + +static int vmDrawMsg_GetSurface(int handle, int index) +{ + struct vm_drawmsg *dm = id_pool_get(&pool, handle); + if (!dm || index < 0 || index >= NR_SURFACES) + return 0; + return dm->surfaces[index]; +} + +static int vmDrawMsg_AddMsg(int handle, struct string *s) +{ + struct vm_drawmsg *dm = id_pool_get(&pool, handle); + if (!dm) + return 0; + string_append(&dm->text, s); + return 1; +} + +static int vmDrawMsg_Draw(int handle) +{ + struct vm_drawmsg *dm = id_pool_get(&pool, handle); + if (!dm) + return 0; + + char *s = dm->text->text; + const int line_space = 2; + while (*s) { + int skiplen = 0, a1, a2, a3; + if (*s != '<') { + char *lb = strchr(s, '<'); + if (lb) { + skiplen = lb - s; + *lb = '\0'; + } else { + skiplen = strlen(s); + } + if (dm->style.drop_shadow) { + struct text_style ts = dm->style.ts; + ts.color = dm->style.drop_shadow_color; + struct vm_surface *sf = vm_surface_get(dm->surfaces[SURFACE_DROP_SHADOW]); + int x = dm->pos.x + dm->style.drop_shadow; + int y = dm->pos.y + dm->style.drop_shadow; + gfx_render_text(&sf->texture, x, y, s, &ts); + } + if (dm->style.bold) { + struct text_style ts = dm->style.ts; + ts.bold_width = dm->style.bold; + ts.color = dm->style.bold_color; + struct vm_surface *sf = vm_surface_get(dm->surfaces[SURFACE_BOLD]); + gfx_render_text(&sf->texture, dm->pos.x, dm->pos.y, s, &ts); + } + struct vm_surface *sf = vm_surface_get(dm->surfaces[SURFACE_TEXT]); + dm->pos.x += gfx_render_text(&sf->texture, dm->pos.x, dm->pos.y, s, &dm->style.ts); + if (lb) + *lb = '<'; + } else if (sscanf(s, "%n", &a1, &a2, &a3, &skiplen) == 3) { + dm->style.ts.color = COLOR(a1, a2, a3, 255); + } else if (sscanf(s, "<@C%d,%d,%d>%n", &a1, &a2, &a3, &skiplen) == 3) { + dm->initial_style.ts.color = dm->style.ts.color = COLOR(a1, a2, a3, 255); + } else if (!strncmp(s, "", 4)) { + skiplen = 4; + dm->style.ts.color = dm->initial_style.ts.color; + } else if (sscanf(s, "%n", &a1, &skiplen) == 1) { + dm->style.bold = a1; + } else if (sscanf(s, "<@E%d>%n", &a1, &skiplen) == 1) { + dm->initial_style.bold = dm->style.bold = a1; + } else if (sscanf(s, "%n", &a1, &a2, &a3, &skiplen) == 3) { + dm->style.bold_color = COLOR(a1, a2, a3, 255); + } else if (sscanf(s, "<@EC%d,%d,%d>%n", &a1, &a2, &a3, &skiplen) == 3) { + dm->initial_style.bold_color = dm->style.bold_color = COLOR(a1, a2, a3, 255); + } else if (sscanf(s, "%n", &a1, &skiplen) == 1) { + dm->style.drop_shadow = a1; + } else if (sscanf(s, "<@K%d>%n", &a1, &skiplen) == 1) { + dm->initial_style.drop_shadow = dm->style.drop_shadow = a1; + } else if (sscanf(s, "%n", &a1, &a2, &a3, &skiplen) == 3) { + dm->style.drop_shadow_color = COLOR(a1, a2, a3, 255); + } else if (sscanf(s, "<@KC%d,%d,%d>%n", &a1, &a2, &a3, &skiplen) == 3) { + dm->initial_style.drop_shadow_color = dm->style.drop_shadow_color = COLOR(a1, a2, a3, 255); + } else if (sscanf(s, "%n", &a1, &skiplen) == 1) { + dm->style.ts.size = a1; + } else if (sscanf(s, "<@S%d>%n", &a1, &skiplen) == 1) { + dm->initial_style.ts.size = dm->style.ts.size = a1; + } else if (sscanf(s, "%n", &a1, &a2, &skiplen) == 2) { + dm->pos = POINT(a1, a2); + } else if (sscanf(s, "<@P%d,%d>%n", &a1, &a2, &skiplen) == 2) { + dm->initial_pos = dm->pos = POINT(a1, a2); + } else if (!strncmp(s, "", 5)) { + skiplen = 5; + dm->pos = dm->initial_pos; + for (int i = 0; i < NR_SURFACES; i++) { + struct vm_surface *dst = vm_surface_get(dm->surfaces[i]); + gfx_fill_amap(&dst->texture, 0, 0, dm->w, dm->h, 0); + } + } else if (!strncmp(s, "", 4)) { + skiplen = 4; + dm->pos = dm->initial_pos; + dm->style = dm->initial_style; + } else if (!strncmp(s, "", 5)) { + // no-op? + skiplen = 5; + } else if (!strncmp(s, "", 3)) { + skiplen = 3; + dm->pos.x = dm->initial_pos.x; + dm->pos.y += dm->style.ts.size + line_space; + } else { + char *rb = strchr(s, '>'); + if (rb) { + WARNING("Unknown command %.*s", ++rb - s, s); + skiplen = rb - s; + } else { + WARNING("Unfinished command in message '%s'", dm->text->text); + break; + } + } + s += skiplen; + } + string_clear(dm->text); + return 0; +} + +static int vmDrawMsg_RenewalRect(int handle, int *x, int *y, int *width, int *height) +{ + struct vm_drawmsg *dm = id_pool_get(&pool, handle); + if (!dm) + return 0; + *x = 0; + *y = 0; + *width = dm->w; + *height = dm->h; + return 1; +} + +HLL_LIBRARY(vmDrawMsg, + HLL_EXPORT(_ModuleFini, vmDrawMsg_ModuleFini), + HLL_EXPORT(New, vmDrawMsg_New), + HLL_EXPORT(Release, vmDrawMsg_Release), + HLL_EXPORT(EnumHandle, vmDrawMsg_EnumHandle), + HLL_EXPORT(Open, vmDrawMsg_Open), + HLL_EXPORT(Close, vmDrawMsg_Close), + HLL_EXPORT(GetNumofSurface, vmDrawMsg_GetNumofSurface), + HLL_EXPORT(GetSurface, vmDrawMsg_GetSurface), + HLL_EXPORT(AddMsg, vmDrawMsg_AddMsg), + HLL_EXPORT(Draw, vmDrawMsg_Draw), + HLL_EXPORT(RenewalRect, vmDrawMsg_RenewalRect) + ); diff --git a/src/hll/vmDrawNumber.c b/src/hll/vmDrawNumber.c new file mode 100644 index 0000000..32be191 --- /dev/null +++ b/src/hll/vmDrawNumber.c @@ -0,0 +1,188 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "system4.h" +#include "system4/cg.h" + +#include "asset_manager.h" +#include "gfx/gfx.h" +#include "hll.h" +#include "id_pool.h" +#include "vmSurface.h" + +enum { + ALIGN_LEFT = 0, + ZERO_PAD = 1, + ALIGN_RIGHT = 2, + ALIGN_CENTER = 4, +}; + +struct vm_drawnumber { + struct texture digits; + struct texture sign; + int surface; + int kind; + int figures; + int space; +}; + +static struct id_pool pool; + +static void vmDrawNumber_New(void) +{ + if (pool.slots) + return; // already initialized + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmDrawNumber_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmDrawNumber_Open(int cg_no, int kind, int figure, int space) +{ + struct cg *cg = asset_cg_load(cg_no); + if (!cg) + return 0; + + int width = cg->metrics.w / 10 * figure; + int height = cg->metrics.h; + + int handle = id_pool_get_unused(&pool); + struct vm_drawnumber *dn = xcalloc(1, sizeof(struct vm_drawnumber)); + id_pool_set(&pool, handle, dn); + + gfx_init_texture_with_cg(&dn->digits, cg); + cg_free(cg); + struct vm_surface *sf = vm_surface_create(width, height); + gfx_init_texture_blank(&sf->texture, width, height); + dn->surface = sf->no; + dn->kind = kind; + dn->figures = figure; + dn->space = space; + return handle; +} + +static void vmDrawNumber_Close(int handle) +{ + struct vm_drawnumber *dn = id_pool_release(&pool, handle); + if (!dn) + return; + gfx_delete_texture(&dn->digits); + gfx_delete_texture(&dn->sign); + vm_surface_delete(dn->surface); + free(dn); +} + +static int vmDrawNumber_Release(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmDrawNumber_Close(i); + id_pool_delete(&pool); + return 1; +} + +static void vmDrawNumber_ModuleFini(void) +{ + vmDrawNumber_Release(); +} + +static int vmDrawNumber_GetSurface(int handle) +{ + struct vm_drawnumber *dn = id_pool_get(&pool, handle); + return dn ? dn->surface : 0; +} + +static void vmDrawNumber_Draw(int handle, int num) +{ + struct vm_drawnumber *dn = id_pool_get(&pool, handle); + if (!dn) + return; + struct vm_surface *sf = vm_surface_get(dn->surface); + if (!sf) + return; + + char buf[16]; + if (dn->kind == ZERO_PAD) { + snprintf(buf, min(sizeof(buf), dn->figures + 1), "%0*d", dn->figures, num); + } else { + snprintf(buf, min(sizeof(buf), dn->figures + 1), "%d", num); + } + + int dw = dn->digits.w / 10; + int w = dw * strlen(buf); + int h = dn->digits.h; + int left; + + switch (dn->kind) { + case ALIGN_LEFT: + case ZERO_PAD: + left = 0; + break; + case ALIGN_RIGHT: + left = sf->texture.w - w; + break; + case ALIGN_CENTER: + left = (sf->texture.w - w) / 2; + break; + default: + WARNING("vmDrawNumber.Draw: unknown kind %d", dn->kind); + left = 0; + break; + } + + gfx_fill_amap(&sf->texture, 0, 0, sf->texture.w, sf->texture.h, 0); + for (int i = 0; buf[i]; i++) { + switch (buf[i]) { + case '-': + gfx_copy_with_alpha_map(&sf->texture, left + i * dw, 0, &dn->sign, 0, 0, dw, h); + break; + default: + gfx_copy_with_alpha_map(&sf->texture, left + i * dw, 0, &dn->digits, (buf[i] - '0') * dw, 0, dw, h); + break; + } + } +} + +int vmDrawNumber_SetSign(int handle, int cg_no) +{ + struct vm_drawnumber *dn = id_pool_get(&pool, handle); + if (!dn) + return 0; + + struct cg *cg = asset_cg_load(cg_no); + if (!cg) + return 0; + + gfx_init_texture_with_cg(&dn->sign, cg); + cg_free(cg); + return 1; +} + +HLL_LIBRARY(vmDrawNumber, + HLL_EXPORT(_ModuleFini, vmDrawNumber_ModuleFini), + HLL_EXPORT(New, vmDrawNumber_New), + HLL_EXPORT(Release, vmDrawNumber_Release), + HLL_EXPORT(EnumHandle, vmDrawNumber_EnumHandle), + HLL_EXPORT(Open, vmDrawNumber_Open), + HLL_EXPORT(Close, vmDrawNumber_Close), + HLL_EXPORT(GetSurface, vmDrawNumber_GetSurface), + HLL_EXPORT(Draw, vmDrawNumber_Draw), + HLL_EXPORT(SetSign, vmDrawNumber_SetSign) + ); diff --git a/src/hll/vmFile.c b/src/hll/vmFile.c new file mode 100644 index 0000000..33dd2da --- /dev/null +++ b/src/hll/vmFile.c @@ -0,0 +1,372 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +#include "system4.h" +#include "system4/buffer.h" +#include "system4/file.h" +#include "system4/string.h" + +#include "hll.h" +#include "id_pool.h" +#include "vm/heap.h" +#include "vm/page.h" +#include "xsystem4.h" + +enum vm_file_mode { + VM_FILE_READ = 1, + VM_FILE_WRITE = 2 +}; + +struct vm_file { + char *path; + FILE *fp; + struct buffer buf; +}; + +static struct id_pool pool; + +static void read_page(struct vm_file *vf, struct page *page); +static void write_page(struct vm_file *vf, struct page *page); + +static void read_value(struct vm_file *vf, union vm_value *v, enum ain_data_type type) +{ + switch (type) { + case AIN_INT: + case AIN_BOOL: + case AIN_LONG_INT: + v->i = buffer_read_int32(&vf->buf); + break; + case AIN_FLOAT: + v->f = buffer_read_float(&vf->buf); + break; + case AIN_STRING: + variable_fini(*v, type); + v->i = heap_alloc_string(buffer_read_string(&vf->buf)); + break; + case AIN_STRUCT: + case AIN_ARRAY_TYPE: + read_page(vf, heap_get_page(v->i)); + break; + default: + VM_ERROR("Unsupported value type %d", type); + } +} + +static void read_page(struct vm_file *vf, struct page *page) +{ + switch (page->type) { + case STRUCT_PAGE: + { + struct ain_struct *s = &ain->structures[page->index]; + for (int i = 0; i < s->nr_members; i++) { + read_value(vf, &page->values[i], s->members[i].type.data); + } + } + break; + case ARRAY_PAGE: + { + enum ain_data_type type = page->array.rank > 1 ? page->a_type : array_type(page->a_type); + for (int i = 0; i < page->nr_vars; i++) { + read_value(vf, &page->values[i], type); + } + } + break; + default: + VM_ERROR("Unsupported page type %d", page->type); + } +} + +static void write_value(struct vm_file *vf, union vm_value v, enum ain_data_type type) +{ + switch (type) { + case AIN_INT: + case AIN_BOOL: + buffer_write_int32(&vf->buf, v.i); + break; + case AIN_FLOAT: + buffer_write_float(&vf->buf, v.f); + break; + case AIN_STRING: + buffer_write_cstringz(&vf->buf, heap_get_string(v.i)->text); + break; + case AIN_STRUCT: + case AIN_ARRAY_TYPE: + write_page(vf, heap_get_page(v.i)); + break; + default: + VM_ERROR("Unsupported value type %d", type); + } +} + +static void write_page(struct vm_file *vf, struct page *page) +{ + switch (page->type) { + case STRUCT_PAGE: + { + struct ain_struct *s = &ain->structures[page->index]; + for (int i = 0; i < s->nr_members; i++) { + write_value(vf, page->values[i], s->members[i].type.data); + } + } + break; + case ARRAY_PAGE: + { + enum ain_data_type type = page->array.rank > 1 ? page->a_type : array_type(page->a_type); + for (int i = 0; i < page->nr_vars; i++) { + write_value(vf, page->values[i], type); + } + } + break; + default: + VM_ERROR("Unsupported page type %d", page->type); + } +} + +static void vmFile_ModuleInit(void) +{ + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmFile_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmFile_Open(struct string *string, int type) +{ + struct vm_file *vf = xcalloc(1, sizeof(struct vm_file)); + char *path = savedir_path(string->text); + vf->path = path; + + if (type == VM_FILE_READ) { + size_t len; + uint8_t *data = file_read(path, &len); + if (!data) { + free(path); + free(vf); + return 0; + } + buffer_init(&vf->buf, data, len); + } else if (type == VM_FILE_WRITE) { + vf->fp = file_open_utf8(path, "wb"); + if (!vf->fp) { + WARNING("Failed to open file '%s': %s", display_utf0(path), strerror(errno)); + free(path); + free(vf); + return 0; + } + } else { + WARNING("Unknown mode in vmFile.Open: %d", type); + return 0; + } + + int handle = id_pool_get_unused(&pool); + id_pool_set(&pool, handle, vf); + return handle; +} + +static void vmFile_Close(int handle) +{ + struct vm_file *vf = id_pool_release(&pool, handle); + if (!vf) + return; + + if (vf->fp) { // write mode + if (fwrite(vf->buf.buf, vf->buf.index, 1, vf->fp) != 1) { + WARNING("%s: fwrite failed: %s", display_utf0(vf->path), strerror(errno)); + } + fclose(vf->fp); + } + free(vf->buf.buf); + free(vf->path); + free(vf); +} + +static void vmFile_ModuleFini(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmFile_Close(i); + id_pool_delete(&pool); +} + +static int vmFile_Encode(int handle, int seed, int rand) +{ + struct vm_file *vf = id_pool_get(&pool, handle); + if (!vf) + return 0; + + size_t len = vf->buf.index; + int32_t *buf = xmalloc(len + 8); + memcpy(buf + 2, vf->buf.buf, len); + free(vf->buf.buf); + vf->buf.buf = (uint8_t*)buf; + vf->buf.index += 8; + + int32_t mask = rand ^ ((rand & 1) ? 0xdf3d1b79 : 0x3ddf791b); + int32_t checksum = 0; + buf[0] = mask; + + len >>= 2; + for (int i = 0; i < len; i++) { + buf[i + 2] ^= mask; + mask = buf[i + 2] ^ seed; + checksum ^= mask; + if (i & 2) + mask ^= i * -3 ^ 0xf7fef7fe; + if (i & 4) + mask = mask << ((3 - i) & 0xf) | mask >> ((i - 3) & 0xf); + } + buf[1] = checksum; + return 1; +} + +static int vmFile_Decode(int handle, int seed) +{ + struct vm_file *vf = id_pool_get(&pool, handle); + if (!vf) + return 0; + + int32_t mask = buffer_read_int32(&vf->buf); + int32_t checksum = buffer_read_int32(&vf->buf); + + int32_t *buf = (int32_t*)buffer_strdata(&vf->buf); + int len = buffer_remaining(&vf->buf) >> 2; + + int32_t sum = 0; + for (int i = 0; i < len; i++) { + buf[i] ^= mask; + mask ^= buf[i] ^ seed; + sum ^= mask; + if (i & 2) + mask ^= i * -3 ^ 0xf7fef7fe; + if (i & 4) + mask = mask << ((3 - i) & 0xf) | mask >> ((i - 3) & 0xf); + } + if (sum != checksum) { + WARNING("%s: checksum error", display_utf0(vf->path)); + return 0; + } + return 1; +} + +//int vmFile_ReadArrayChar(int handle, struct page **pIVMArray); +//int vmFile_ReadArrayShort(int handle, struct page **pIVMArray); +//int vmFile_ReadArrayInt(int handle, struct page **pIVMArray); +//int vmFile_ReadArrayFloat(int handle, struct page **pIVMArray); +//int vmFile_ReadArrayString(int handle, struct page **pIVMArray); +//int vmFile_ReadArrayStruct(int handle, struct page **pIVMArray); + +static int vmFile_ReadStruct(int handle, struct page **_page) +{ + struct vm_file *vf = id_pool_get(&pool, handle); + if (!vf) + return 0; + + struct page *page = *_page; + if (page->type != STRUCT_PAGE) { + VM_ERROR("vmFile.ReadStruct of non-struct"); + } + + read_page(vf, page); + return 1; +} + +//int vmFile_ReadGlobal(int handle, IMainSystem pIMainSystem); +//int vmFile_WriteArrayChar(int handle, struct page *pIVMArray); +//int vmFile_WriteArrayShort(int handle, struct page *pIVMArray); +//int vmFile_WriteArrayInt(int handle, struct page *pIVMArray); +//int vmFile_WriteArrayFloat(int handle, struct page *pIVMArray); +//int vmFile_WriteArrayString(int handle, struct page *pIVMArray); +//int vmFile_WriteArrayStruct(int handle, struct page *pIVMArray); + +static int vmFile_WriteStruct(int handle, struct page *page) +{ + struct vm_file *vf = id_pool_get(&pool, handle); + if (!vf) + return 0; + write_page(vf, page); + return 1; +} + +//int vmFile_WriteGlobal(int handle, IMainSystem pIMainSystem); +//int vmFile_SeekChar(int handle, int nPos, int nAbsolute); +//int vmFile_SeekShort(int handle, int nPos, int nAbsolute); +//int vmFile_SeekInt(int handle, int nPos, int nAbsolute); +//int vmFile_SeekFloat(int handle, int nPos, int nAbsolute); +//int vmFile_SeekString(int handle, int nPos, int nAbsolute); +//int vmFile_SizeChar(int handle); +//int vmFile_SizeShort(int handle); +//int vmFile_SizeInt(int handle); +//int vmFile_SizeFloat(int handle); +//int vmFile_SizeString(int handle); +//int vmFile_Copy(struct string *pISString, struct string *pIDString); + +static int vmFile_Delete(struct string *string) +{ + char *path = savedir_path(string->text); + int r = !remove_utf8(path); + free(path); + return r; +} + +//int vmFile_GetTime(struct string *pIString, struct page **pIVMStruct); +//int vmFile_Find(struct string *pIWildString, struct string **pIString, int *pnCount); +//int vmFile_MakeDirectory(struct string *pIString); + +HLL_LIBRARY(vmFile, + HLL_EXPORT(_ModuleInit, vmFile_ModuleInit), + HLL_EXPORT(_ModuleFini, vmFile_ModuleFini), + HLL_EXPORT(EnumHandle, vmFile_EnumHandle), + HLL_EXPORT(Open, vmFile_Open), + HLL_EXPORT(Close, vmFile_Close), + HLL_EXPORT(Encode, vmFile_Encode), + HLL_EXPORT(Decode, vmFile_Decode), + HLL_TODO_EXPORT(ReadArrayChar, vmFile_ReadArrayChar), + HLL_TODO_EXPORT(ReadArrayShort, vmFile_ReadArrayShort), + HLL_TODO_EXPORT(ReadArrayInt, vmFile_ReadArrayInt), + HLL_TODO_EXPORT(ReadArrayFloat, vmFile_ReadArrayFloat), + HLL_TODO_EXPORT(ReadArrayString, vmFile_ReadArrayString), + HLL_TODO_EXPORT(ReadArrayStruct, vmFile_ReadArrayStruct), + HLL_EXPORT(ReadStruct, vmFile_ReadStruct), + HLL_TODO_EXPORT(ReadGlobal, vmFile_ReadGlobal), + HLL_TODO_EXPORT(WriteArrayChar, vmFile_WriteArrayChar), + HLL_TODO_EXPORT(WriteArrayShort, vmFile_WriteArrayShort), + HLL_TODO_EXPORT(WriteArrayInt, vmFile_WriteArrayInt), + HLL_TODO_EXPORT(WriteArrayFloat, vmFile_WriteArrayFloat), + HLL_TODO_EXPORT(WriteArrayString, vmFile_WriteArrayString), + HLL_TODO_EXPORT(WriteArrayStruct, vmFile_WriteArrayStruct), + HLL_EXPORT(WriteStruct, vmFile_WriteStruct), + HLL_TODO_EXPORT(WriteGlobal, vmFile_WriteGlobal), + HLL_TODO_EXPORT(SeekChar, vmFile_SeekChar), + HLL_TODO_EXPORT(SeekShort, vmFile_SeekShort), + HLL_TODO_EXPORT(SeekInt, vmFile_SeekInt), + HLL_TODO_EXPORT(SeekFloat, vmFile_SeekFloat), + HLL_TODO_EXPORT(SeekString, vmFile_SeekString), + HLL_TODO_EXPORT(SizeChar, vmFile_SizeChar), + HLL_TODO_EXPORT(SizeShort, vmFile_SizeShort), + HLL_TODO_EXPORT(SizeInt, vmFile_SizeInt), + HLL_TODO_EXPORT(SizeFloat, vmFile_SizeFloat), + HLL_TODO_EXPORT(SizeString, vmFile_SizeString), + HLL_TODO_EXPORT(Copy, vmFile_Copy), + HLL_EXPORT(Delete, vmFile_Delete), + HLL_TODO_EXPORT(GetTime, vmFile_GetTime), + HLL_TODO_EXPORT(Find, vmFile_Find), + HLL_TODO_EXPORT(MakeDirectory, vmFile_MakeDirectory) + ); diff --git a/src/hll/vmGraph.c b/src/hll/vmGraph.c new file mode 100644 index 0000000..181a499 --- /dev/null +++ b/src/hll/vmGraph.c @@ -0,0 +1,214 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "gfx/gfx.h" +#include "vmSurface.h" +#include "hll.h" + +HLL_QUIET_UNIMPLEMENTED( , void, vmGraph, Init, void *imainsystem); +//void vmGraph_SetUseCPUEx(int nUse); + +static void vmGraph_Copy(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height) +{ + struct vm_surface *dst = vm_surface_get(dst_surface); + struct vm_surface *src = vm_surface_get(src_surface); + if (!dst || !src) + return; + gfx_copy_with_alpha_map(&dst->texture, dx, dy, &src->texture, sx, sy, width, height); +} + +static void vmGraph_CopyPixelMap(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height) +{ + struct vm_surface *dst = vm_surface_get(dst_surface); + struct vm_surface *src = vm_surface_get(src_surface); + if (!dst || !src) + return; + gfx_copy(&dst->texture, dx, dy, &src->texture, sx, sy, width, height); +} + +static void vmGraph_CopyAlphaMap(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height) +{ + struct vm_surface *dst = vm_surface_get(dst_surface); + struct vm_surface *src = vm_surface_get(src_surface); + if (!dst || !src) + return; + gfx_copy_amap(&dst->texture, dx, dy, &src->texture, sx, sy, width, height); +} + +//void vmGraph_CopyBright(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int nRate); + +static void vmGraph_CopySprite(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int r, int g, int b) +{ + struct vm_surface *dst = vm_surface_get(dst_surface); + struct vm_surface *src = vm_surface_get(src_surface); + if (!dst || !src) + return; + gfx_copy_sprite(&dst->texture, dx, dy, &src->texture, sx, sy, width, height, COLOR(r, g, b, 0)); +} + +//void vmGraph_Blend(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int alpha); +//void vmGraph_BlendSrcBright(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int alpha, int nRate); +//void vmGraph_BlendAddSatur(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height); + +static void vmGraph_BlendAlphaMap(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height) +{ + struct vm_surface *dst = vm_surface_get(dst_surface); + struct vm_surface *src = vm_surface_get(src_surface); + if (!dst || !src) + return; + gfx_blend_amap(&dst->texture, dx, dy, &src->texture, sx, sy, width, height); +} + +//void vmGraph_BlendAlphaMapSrcOnly(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height); +//void vmGraph_BlendAlphaMapColor(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int r, int g, int b); +//void vmGraph_BlendAlphaMapColorAlpha(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int r, int g, int b, int alpha); +//void vmGraph_BlendAlphaMapAlpha(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int alpha); +//void vmGraph_BlendAlphaMapBright(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int nRate); +//void vmGraph_BlendAlphaMapAlphaSrcBright(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int alpha, int nRate); +//void vmGraph_BlendUseAMapColor(int dst_surface, int dx, int dy, int width, int height, int hAlphaSurface, int nAx, int nAy, int r, int g, int b, int alpha); +//void vmGraph_BlendScreen(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height); +//void vmGraph_BlendMultiply(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height); +//void vmGraph_BlendScreenAlpha(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height, int alpha); + +static void vmGraph_Fill(int surface, int x, int y, int width, int height, int r, int g, int b, int alpha) +{ + struct vm_surface *dst = vm_surface_get(surface); + if (!dst) + return; + gfx_fill_with_alpha(&dst->texture, x, y, width, height, r, g, b, alpha); +} + +static void vmGraph_FillPixelMap(int surface, int x, int y, int width, int height, int r, int g, int b) +{ + struct vm_surface *dst = vm_surface_get(surface); + if (!dst) + return; + gfx_fill(&dst->texture, x, y, width, height, r, g, b); +} + +static void vmGraph_FillAlphaMap(int surface, int x, int y, int width, int height, int alpha) +{ + struct vm_surface *dst = vm_surface_get(surface); + if (!dst) + return; + gfx_fill_amap(&dst->texture, x, y, width, height, alpha); +} + +static void vmGraph_FillAlphaColor(int surface, int x, int y, int width, int height, int r, int g, int b, int rate) +{ + struct vm_surface *dst = vm_surface_get(surface); + if (!dst) + return; + gfx_fill_alpha_color(&dst->texture, x, y, width, height, r, g, b, rate); +} + +//void vmGraph_SaturDP_DPxSA(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height); +//void vmGraph_ScreenDA_DAxSA(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height); + +static void vmGraph_AddDA_DAxSA(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height) +{ + struct vm_surface *dst = vm_surface_get(dst_surface); + struct vm_surface *src = vm_surface_get(src_surface); + if (!dst || !src) + return; + gfx_add_da_daxsa(&dst->texture, dx, dy, &src->texture, sx, sy, width, height); +} + +//void vmGraph_SubDA_DAxSA(int dst_surface, int dx, int dy, int src_surface, int sx, int sy, int width, int height); +//void vmGraph_BrightDestOnly(int surface, int x, int y, int width, int height, int nRate); +//void vmGraph_CopyTextureWrap(int dst_surface, int dx, int dy, int d_width, int d_height, int src_surface, int sx, int sy, int s_width, int s_height, int nU, int nV); +//void vmGraph_CopyTextureWrapAlpha(int dst_surface, int dx, int dy, int d_width, int d_height, int src_surface, int sx, int sy, int s_width, int s_height, int nU, int nV, int alpha); + +static void vmGraph_CopyStretch(int surface, int dx, int dy, int d_width, int d_height, int src_surface, float sx, float sy, float s_width, float s_height) +{ + struct vm_surface *dst = vm_surface_get(surface); + struct vm_surface *src = vm_surface_get(src_surface); + if (!dst || !src) + return; + + // Use nearest neighbor interpolation to avoid magenta edges. + glBindTexture(GL_TEXTURE_2D, src->texture.handle); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); + + gfx_copy_stretch( + &dst->texture, dx, dy, d_width, d_height, + &src->texture, sx, sy, s_width, s_height); + + glBindTexture(GL_TEXTURE_2D, src->texture.handle); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); +} + +//void vmGraph_CopyStretchBlend(int surface, int dx, int dy, int d_width, int d_height, int src_surface, float sx, float sy, float s_width, float s_height, int alpha); +//void vmGraph_CopyStretchBlendAlphaMap(int surface, int dx, int dy, int d_width, int d_height, int src_surface, float sx, float sy, float s_width, float s_height); +HLL_WARN_UNIMPLEMENTED( , void, vmGraph, SetClickCancel, int click); +//int vmGraph_EffectCopy(int dx, int dy, int src_surface, int sx, int sy, int width, int height, int nEffect, int nTotalTime); +//int vmGraph_GetMainWidth(void); +//int vmGraph_GetMainHeight(void); +//int vmGraph_GetMainBpp(void); + +void vmGraph_Update(int x, int y, int width, int height) +{ + gfx_swap(); +} + +HLL_LIBRARY(vmGraph, + HLL_EXPORT(Init, vmGraph_Init), + HLL_TODO_EXPORT(SetUseCPUEx, vmGraph_SetUseCPUEx), + HLL_EXPORT(Copy, vmGraph_Copy), + HLL_EXPORT(CopyPixelMap, vmGraph_CopyPixelMap), + HLL_EXPORT(CopyAlphaMap, vmGraph_CopyAlphaMap), + HLL_TODO_EXPORT(CopyBright, vmGraph_CopyBright), + HLL_EXPORT(CopySprite, vmGraph_CopySprite), + HLL_TODO_EXPORT(Blend, vmGraph_Blend), + HLL_TODO_EXPORT(BlendSrcBright, vmGraph_BlendSrcBright), + HLL_TODO_EXPORT(BlendAddSatur, vmGraph_BlendAddSatur), + HLL_EXPORT(BlendAlphaMap, vmGraph_BlendAlphaMap), + HLL_TODO_EXPORT(BlendAlphaMapSrcOnly, vmGraph_BlendAlphaMapSrcOnly), + HLL_TODO_EXPORT(BlendAlphaMapColor, vmGraph_BlendAlphaMapColor), + HLL_TODO_EXPORT(BlendAlphaMapColorAlpha, vmGraph_BlendAlphaMapColorAlpha), + HLL_TODO_EXPORT(BlendAlphaMapAlpha, vmGraph_BlendAlphaMapAlpha), + HLL_TODO_EXPORT(BlendAlphaMapBright, vmGraph_BlendAlphaMapBright), + HLL_TODO_EXPORT(BlendAlphaMapAlphaSrcBright, vmGraph_BlendAlphaMapAlphaSrcBright), + HLL_TODO_EXPORT(BlendUseAMapColor, vmGraph_BlendUseAMapColor), + HLL_TODO_EXPORT(BlendScreen, vmGraph_BlendScreen), + HLL_TODO_EXPORT(BlendMultiply, vmGraph_BlendMultiply), + HLL_TODO_EXPORT(BlendScreenAlpha, vmGraph_BlendScreenAlpha), + HLL_EXPORT(Fill, vmGraph_Fill), + HLL_EXPORT(FillPixelMap, vmGraph_FillPixelMap), + HLL_EXPORT(FillAlphaMap, vmGraph_FillAlphaMap), + HLL_EXPORT(FillAlphaColor, vmGraph_FillAlphaColor), + HLL_TODO_EXPORT(SaturDP_DPxSA, vmGraph_SaturDP_DPxSA), + HLL_TODO_EXPORT(ScreenDA_DAxSA, vmGraph_ScreenDA_DAxSA), + HLL_EXPORT(AddDA_DAxSA, vmGraph_AddDA_DAxSA), + HLL_TODO_EXPORT(SubDA_DAxSA, vmGraph_SubDA_DAxSA), + HLL_TODO_EXPORT(BrightDestOnly, vmGraph_BrightDestOnly), + HLL_TODO_EXPORT(CopyTextureWrap, vmGraph_CopyTextureWrap), + HLL_TODO_EXPORT(CopyTextureWrapAlpha, vmGraph_CopyTextureWrapAlpha), + HLL_EXPORT(CopyStretch, vmGraph_CopyStretch), + HLL_TODO_EXPORT(CopyStretchBlend, vmGraph_CopyStretchBlend), + HLL_TODO_EXPORT(CopyStretchBlendAlphaMap, vmGraph_CopyStretchBlendAlphaMap), + HLL_EXPORT(SetClickCancel, vmGraph_SetClickCancel), + HLL_TODO_EXPORT(EffectCopy, vmGraph_EffectCopy), + HLL_EXPORT(GetMainSurface, vm_surface_get_main_surface), + HLL_TODO_EXPORT(GetMainWidth, vmGraph_GetMainWidth), + HLL_TODO_EXPORT(GetMainHeight, vmGraph_GetMainHeight), + HLL_TODO_EXPORT(GetMainBpp, vmGraph_GetMainBpp), + HLL_EXPORT(Update, vmGraph_Update) + ); diff --git a/src/hll/vmGraphQuake.c b/src/hll/vmGraphQuake.c new file mode 100644 index 0000000..ed94162 --- /dev/null +++ b/src/hll/vmGraphQuake.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "hll.h" + +HLL_WARN_UNIMPLEMENTED(, void, vmGraphQuake, SetMode, int mode); +//void vmGraphQuake_SetAmp(int nAmp); +HLL_WARN_UNIMPLEMENTED(, void, vmGraphQuake, SetAmpX, int amp_x); +HLL_WARN_UNIMPLEMENTED(, void, vmGraphQuake, SetAmpY, int amp_y); +//void vmGraphQuake_SetCycle(int nCycle); +//int vmGraphQuake_GetMode(void); +//int vmGraphQuake_GetAmp(void); +//int vmGraphQuake_GetAmpX(void); +//int vmGraphQuake_GetAmpY(void); +//int vmGraphQuake_GetCycle(void); + +HLL_LIBRARY(vmGraphQuake, + HLL_EXPORT(SetMode, vmGraphQuake_SetMode), + HLL_TODO_EXPORT(SetAmp, vmGraphQuake_SetAmp), + HLL_EXPORT(SetAmpX, vmGraphQuake_SetAmpX), + HLL_EXPORT(SetAmpY, vmGraphQuake_SetAmpY), + HLL_TODO_EXPORT(SetCycle, vmGraphQuake_SetCycle), + HLL_TODO_EXPORT(GetMode, vmGraphQuake_GetMode), + HLL_TODO_EXPORT(GetAmp, vmGraphQuake_GetAmp), + HLL_TODO_EXPORT(GetAmpX, vmGraphQuake_GetAmpX), + HLL_TODO_EXPORT(GetAmpY, vmGraphQuake_GetAmpY), + HLL_TODO_EXPORT(GetCycle, vmGraphQuake_GetCycle) + ); diff --git a/src/hll/vmKey.c b/src/hll/vmKey.c new file mode 100644 index 0000000..10ce7e8 --- /dev/null +++ b/src/hll/vmKey.c @@ -0,0 +1,133 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "system4.h" + +#include "hll.h" +#include "id_pool.h" +#include "input.h" +#include "vm.h" +#include "xsystem4.h" + +#define MAXENT 32 + +struct vm_key { + int size; + int win[MAXENT]; + int ret[MAXENT]; +}; + +static struct id_pool pool; + +static void handle_events_throttled(void) +{ + // To prevent taking 100% CPU time in busy input loops, + // sleep 10ms every 30 input event checks. + static int count; + if (++count == 30) { + count = 0; + vm_sleep(10); + } + handle_events(); +} + +static void vmKey_Init(possibly_unused void *imainsystem) +{ + if (pool.slots) + return; // already initialized + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmKey_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmKey_Open(void) +{ + int no = id_pool_get_unused(&pool); + struct vm_key *vk = xcalloc(1, sizeof(struct vm_key)); + id_pool_set(&pool, no, vk); + return no; +} + +static void vmKey_Close(int handle) +{ + struct vm_key *vk = id_pool_release(&pool, handle); + if (vk) + free(vk); +} + +static void vmKey_ModuleFini(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmKey_Close(i); + id_pool_delete(&pool); +} + +static int vmKey_Set(int handle, int win_key, int ret_key) +{ + struct vm_key *vk = id_pool_get(&pool, handle); + if (!vk) + return 0; + if (vk->size + 1 >= MAXENT) + VM_ERROR("too many keys"); + vk->win[vk->size] = win_key; + vk->ret[vk->size] = ret_key; + vk->size++; + return 1; +} + +static int vmKey_Get(int handle) +{ + struct vm_key *vk = id_pool_get(&pool, handle); + if (!vk) + return 0; + + handle_events_throttled(); + int ret = 0; + for (int i = 0; i < vk->size; i++) { + if (key_is_down(vk->win[i])) { + ret |= vk->ret[i]; + } + } + return ret; +} + +static int vmKey_GetWheelCount(void) +{ + int forward, back; + handle_events_throttled(); + mouse_get_wheel(&forward, &back); + mouse_clear_wheel(); + return back - forward; +} + +//void vmKey_ClearBuffer(void); + +HLL_LIBRARY(vmKey, + HLL_EXPORT(_ModuleFini, vmKey_ModuleFini), + HLL_EXPORT(Init, vmKey_Init), + HLL_EXPORT(EnumHandle, vmKey_EnumHandle), + HLL_EXPORT(Open, vmKey_Open), + HLL_EXPORT(Close, vmKey_Close), + HLL_EXPORT(Set, vmKey_Set), + HLL_EXPORT(Get, vmKey_Get), + HLL_EXPORT(GetWheelCount, vmKey_GetWheelCount), + HLL_TODO_EXPORT(ClearBuffer, vmKey_ClearBuffer) + ); diff --git a/src/hll/vmMapLoader.c b/src/hll/vmMapLoader.c new file mode 100644 index 0000000..cf11138 --- /dev/null +++ b/src/hll/vmMapLoader.c @@ -0,0 +1,231 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include + +#include "system4/file.h" +#include "system4/mt19937int.h" +#include "system4/little_endian.h" + +#include "hll.h" +#include "xsystem4.h" + +/* + * struct MapHeader { + * char magic[4]; // "Map\0" + * // the below are encrypted + * uint32_t width; + * uint32_t height; + * uint32_t cg_table_offset; + * uint32_t move_table_offset; + * uint32_t figure_table_offset; + * uint32_t info_table_offset; + * uint32_t map_no; + * }; + * + * struct CGTable { + * uint32_t count; + * uint32_t cg[count]; + * }; + * + * struct MoveTable { + * bool movable[height][width]; + * }; + * + * struct FigureTable { + * uint32_t count; + * struct { + * uint8_t x; + * uint8_t y; + * uint16_t unit; + * } figures[count]; + * }; + * + * struct InfoTable { + * uint32_t item; + * uint32_t gold; + * uint32_t turn; + * uint32_t level; + * uint32_t unknown; // checksum? + * }; + */ + +static uint8_t *map_data; +static size_t map_size; + +static char *mapfile_path(int map_no) +{ + char buf[32]; + sprintf(buf, "Map/%04d.map", map_no); + return gamedir_path(buf); +} + +HLL_QUIET_UNIMPLEMENTED(, void, vmMapLoader,Init, void *imainsystem, struct string *string); + +static int vmMapLoader_Exist(int map_no) +{ + char *path = mapfile_path(map_no); + bool result = file_exists(path); + free(path); + return result; +} + +static int vmMapLoader_New(int map_no) +{ + if (map_data) + free(map_data); + + char *path = mapfile_path(map_no); + map_data = file_read(path, &map_size); + if (!map_data) { + WARNING("Cannot read %s", path); + } else if (memcmp(map_data, "Map", 4)) { + WARNING("%s: Wrong magic bytes", path); + free(map_data); + map_data = NULL; + } else { + mt19937_xorcode(map_data + 4, map_size - 4, 12753); + } + + free(path); + return !!map_data; +} + +void vmMapLoader_Release(void) +{ + if (map_data) { + free(map_data); + map_data = NULL; + } +} + +static int vmMapLoader_GetWidth(void) +{ + if (!map_data) + return -1; + return LittleEndian_getDW(map_data, 4); +} + +static int vmMapLoader_GetHeight(void) +{ + if (!map_data) + return -1; + return LittleEndian_getDW(map_data, 8); +} + +static int vmMapLoader_GetBaseCG(int index) +{ + if (!map_data) + return -1; + int nr_base_cg = LittleEndian_getDW(map_data, 32); + if (index < 0 || index >= nr_base_cg) + return -1; + return LittleEndian_getDW(map_data, 36 + index * 4); +} + +static int vmMapLoader_GetNumofBaseCG(void) +{ + if (!map_data) + return -1; + return LittleEndian_getDW(map_data, 32); +} + +static int vmMapLoader_IsMove(int x, int y) +{ + if (!map_data) + return -1; + int w = LittleEndian_getDW(map_data, 4); + int h = LittleEndian_getDW(map_data, 8); + if (x < 0 || x >= w || y < 0 || y > h) + return 0; + uint8_t *table = map_data + LittleEndian_getDW(map_data, 16); + return table[y * w + x]; +} + +static int vmMapLoader_GetFigure(int x, int y) +{ + if (!map_data) + return 0; + + int offset = LittleEndian_getDW(map_data, 20); + int num = LittleEndian_getDW(map_data, offset); + uint8_t *table = map_data + offset + 4; + + for (int i = 0; i < num; i++) { + if (x == table[i * 4] && y == table[i * 4 + 1]) + return LittleEndian_getW(table, i * 4 + 2); + } + return 0; +} + +static int vmMapLoader_GetItemNum(void) +{ + if (!map_data) + return -1; + int offset = LittleEndian_getDW(map_data, 24); + return LittleEndian_getDW(map_data, offset + 0); +} + +static int vmMapLoader_GetGoldNum(void) +{ + if (!map_data) + return -1; + int offset = LittleEndian_getDW(map_data, 24); + return LittleEndian_getDW(map_data, offset + 4); +} + +static int vmMapLoader_GetTurnNum(void) +{ + if (!map_data) + return -1; + int offset = LittleEndian_getDW(map_data, 24); + return LittleEndian_getDW(map_data, offset + 8); +} + +static int vmMapLoader_GetLevel(void) +{ + if (!map_data) + return -1; + int offset = LittleEndian_getDW(map_data, 24); + return LittleEndian_getDW(map_data, offset + 12); +} + + +static int vmMapLoader_GetID(void) +{ + if (!map_data) + return -1; + return LittleEndian_getDW(map_data, 28); +} + +HLL_LIBRARY(vmMapLoader, + HLL_EXPORT(Init, vmMapLoader_Init), + HLL_EXPORT(Exist, vmMapLoader_Exist), + HLL_EXPORT(New, vmMapLoader_New), + HLL_EXPORT(Release, vmMapLoader_Release), + HLL_EXPORT(GetWidth, vmMapLoader_GetWidth), + HLL_EXPORT(GetHeight, vmMapLoader_GetHeight), + HLL_EXPORT(GetBaseCG, vmMapLoader_GetBaseCG), + HLL_EXPORT(GetNumofBaseCG, vmMapLoader_GetNumofBaseCG), + HLL_EXPORT(IsMove, vmMapLoader_IsMove), + HLL_EXPORT(GetFigure, vmMapLoader_GetFigure), + HLL_EXPORT(GetItemNum, vmMapLoader_GetItemNum), + HLL_EXPORT(GetGoldNum, vmMapLoader_GetGoldNum), + HLL_EXPORT(GetTurnNum, vmMapLoader_GetTurnNum), + HLL_EXPORT(GetLevel, vmMapLoader_GetLevel), + HLL_EXPORT(GetID, vmMapLoader_GetID) + ); diff --git a/src/hll/vmMsgLog.c b/src/hll/vmMsgLog.c new file mode 100644 index 0000000..ddcf480 --- /dev/null +++ b/src/hll/vmMsgLog.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "system4/ain.h" +#include "system4/string.h" + +#include "hll.h" +#include "id_pool.h" +#include "vm.h" +#include "vm/page.h" + +struct vm_msglog { + struct page *array; // backing store + int ptr; +}; + +static struct id_pool pool; + +static void vmMsgLog_Init(possibly_unused void *imainsystem) +{ + if (pool.slots) + return; // already initialized + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmMsgLog_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmMsgLog_Open(struct page **array) +{ + int no = id_pool_get_unused(&pool); + struct vm_msglog *log = xcalloc(1, sizeof(struct vm_msglog)); + id_pool_set(&pool, no, log); + log->array = *array; + log->ptr = 0; + return no; +} + +static void vmMsgLog_Close(int handle) +{ + struct vm_msglog *log = id_pool_release(&pool, handle); + if (log) + free(log); +} + +static void vmMsgLog_ModuleFini(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmMsgLog_Close(i); + id_pool_delete(&pool); +} + +static int vmMsgLog_Set(int handle, int msg_num) +{ + struct vm_msglog *log = id_pool_get(&pool, handle); + if (!log) + return 0; + + if (--log->ptr < 0) + log->ptr = log->array->nr_vars - 1; + log->array->values[log->ptr].i = msg_num; + return 1; +} + +static int vmMsgLog_Get(int handle, int index) +{ + struct vm_msglog *log = id_pool_get(&pool, handle); + if (!log) + return -1; + + int i = (index + log->ptr) % log->array->nr_vars; + return log->array->values[i].i; +} + +static struct string *vmMsgLog_MsgNumToString(int msg_num) +{ + if (msg_num < 0 || msg_num >= ain->nr_messages) + return string_ref(&EMPTY_STRING); + return string_ref(ain->messages[msg_num]); +} + +HLL_LIBRARY(vmMsgLog, + HLL_EXPORT(_ModuleFini, vmMsgLog_ModuleFini), + HLL_EXPORT(Init, vmMsgLog_Init), + HLL_EXPORT(EnumHandle, vmMsgLog_EnumHandle), + HLL_EXPORT(Open, vmMsgLog_Open), + HLL_EXPORT(Close, vmMsgLog_Close), + HLL_EXPORT(Set, vmMsgLog_Set), + HLL_EXPORT(Get, vmMsgLog_Get), + HLL_EXPORT(MsgNumToString, vmMsgLog_MsgNumToString) + ); diff --git a/src/hll/vmMsgSkip.c b/src/hll/vmMsgSkip.c new file mode 100644 index 0000000..8763481 --- /dev/null +++ b/src/hll/vmMsgSkip.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "hll.h" + +HLL_WARN_UNIMPLEMENTED(, void, vmMsgSkip, Init, void *imainsystem); +//int vmMsgSkip_EnumHandle(void); +//int vmMsgSkip_Open(struct string *pIString, int nOption); +//void vmMsgSkip_Close(int hMsgSkip); +//int vmMsgSkip_Query(int hMsgSkip, int nMsgNum); +//void vmMsgSkip_SetEnable(int nEnable); +HLL_QUIET_UNIMPLEMENTED(, void, vmMsgSkip, SetState, int state); +//int vmMsgSkip_GetEnable(void); +//int vmMsgSkip_GetState(void); + +HLL_LIBRARY(vmMsgSkip, + HLL_EXPORT(Init, vmMsgSkip_Init), + HLL_TODO_EXPORT(EnumHandle, vmMsgSkip_EnumHandle), + HLL_TODO_EXPORT(Open, vmMsgSkip_Open), + HLL_TODO_EXPORT(Close, vmMsgSkip_Close), + HLL_TODO_EXPORT(Query, vmMsgSkip_Query), + HLL_TODO_EXPORT(SetEnable, vmMsgSkip_SetEnable), + HLL_EXPORT(SetState, vmMsgSkip_SetState), + HLL_TODO_EXPORT(GetEnable, vmMsgSkip_GetEnable), + HLL_TODO_EXPORT(GetState, vmMsgSkip_GetState) + ); diff --git a/src/hll/vmMusic.c b/src/hll/vmMusic.c new file mode 100644 index 0000000..f1b1c9b --- /dev/null +++ b/src/hll/vmMusic.c @@ -0,0 +1,85 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "system4.h" + +#include "hll.h" +#include "audio.h" + +static int max_channel; +static int *current; + +static void vmMusic_Init(int max_channel_, possibly_unused void *imainsystem) +{ + audio_init(); + max_channel = max_channel_; + current = xcalloc(max_channel, sizeof(int)); +} + +static int vmMusic_Prepare(int channel, int track) +{ + if (channel < 0 || channel >= max_channel) + return 0; + if (current[channel] == track) + return 1; // Keep playing current music. + int r = bgm_prepare(channel, track); + if (r) + current[channel] = track; + return r; +} + +static int vmMusic_Play(int channel) +{ + return bgm_play(channel); +} + +static int vmMusic_Stop(int channel) +{ + return bgm_stop(channel); +} + +static int vmMusic_IsPlay(int channel) +{ + return bgm_is_playing(channel); +} + +//int vmMusic_SetLoop(int channel, int nLoop); +//int vmMusic_GetLoop(int channel); + +static int vmMusic_Fade(int channel, int time, int volume, int stop) +{ + return bgm_fade(channel, time, volume, stop); +} + +//int vmMusic_StopFade(int channel); +//int vmMusic_IsFade(int channel); +//int vmMusic_GetPos(int channel); +//int vmMusic_GetLength(int channel); + +HLL_LIBRARY(vmMusic, + HLL_EXPORT(Init, vmMusic_Init), + HLL_EXPORT(Prepare, vmMusic_Prepare), + HLL_EXPORT(Play, vmMusic_Play), + HLL_EXPORT(Stop, vmMusic_Stop), + HLL_EXPORT(IsPlay, vmMusic_IsPlay), + HLL_TODO_EXPORT(SetLoop, vmMusic_SetLoop), + HLL_TODO_EXPORT(GetLoop, vmMusic_GetLoop), + HLL_EXPORT(Fade, vmMusic_Fade), + HLL_TODO_EXPORT(StopFade, vmMusic_StopFade), + HLL_TODO_EXPORT(IsFade, vmMusic_IsFade), + HLL_TODO_EXPORT(GetPos, vmMusic_GetPos), + HLL_TODO_EXPORT(GetLength, vmMusic_GetLength) + ); diff --git a/src/hll/vmSound.c b/src/hll/vmSound.c new file mode 100644 index 0000000..2d3e8f4 --- /dev/null +++ b/src/hll/vmSound.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "audio.h" +#include "hll.h" +#include "ChrLoader.h" + +static int ring_pos = 0; + +static void vmSound_Init(possibly_unused void *imainsystem) +{ + audio_init(); +} + +//void vmSound_Enable(int nEnable); +//void vmSound_SetType(int nType); + +static int vmSound_Load(int channel, int num) +{ + return wav_prepare(channel, num); +} + +static int vmSound_LoadMemory(int channel, int memory) +{ + struct archive_data *dfile = chr_loader_get_blob_as_archive_data(memory); + if (!dfile) + return 0; + return wav_prepare_from_archive_data(channel, dfile); +} + +static void vmSound_Unload(int channel, possibly_unused int length) +{ + wav_unprepare(channel); +} + +static int vmSound_Play(int channel, possibly_unused int length) +{ + wav_stop(channel); + return wav_play(channel); +} + +static int vmSound_RingPlay(int channel, int ring) +{ + channel += ring_pos++ % ring; + wav_stop(channel); + return wav_play(channel); +} + +//int vmSound_Stop(int channel, int nLength); +//int vmSound_IsPlay(int channel, int nLength); +//void vmSound_Wait(int channel, int nLength); +//int vmSound_Fade(int channel, int nLength, int nTime, int nVolume, int nStopFlag); +//int vmSound_StopFade(int channel, int nLength); +//int vmSound_IsFade(int channel, int nLength); +//int vmSound_ReverseLR(int channel, int nLength); + +HLL_LIBRARY(vmSound, + HLL_EXPORT(Init, vmSound_Init), + HLL_TODO_EXPORT(Enable, vmSound_Enable), + HLL_TODO_EXPORT(SetType, vmSound_SetType), + HLL_EXPORT(Load, vmSound_Load), + HLL_EXPORT(LoadMemory, vmSound_LoadMemory), + HLL_EXPORT(Unload, vmSound_Unload), + HLL_EXPORT(Play, vmSound_Play), + HLL_EXPORT(RingPlay, vmSound_RingPlay), + HLL_TODO_EXPORT(Stop, vmSound_Stop), + HLL_TODO_EXPORT(IsPlay, vmSound_IsPlay), + HLL_TODO_EXPORT(Wait, vmSound_Wait), + HLL_TODO_EXPORT(Fade, vmSound_Fade), + HLL_TODO_EXPORT(StopFade, vmSound_StopFade), + HLL_TODO_EXPORT(IsFade, vmSound_IsFade), + HLL_TODO_EXPORT(ReverseLR, vmSound_ReverseLR) + ); diff --git a/src/hll/vmSprite.c b/src/hll/vmSprite.c new file mode 100644 index 0000000..9d3ebb5 --- /dev/null +++ b/src/hll/vmSprite.c @@ -0,0 +1,628 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "cJSON.h" +#include "effect.h" +#include "gfx/gfx.h" +#include "hll.h" +#include "id_pool.h" +#include "input.h" +#include "json.h" +#include "sact.h" +#include "scene.h" +#include "vm/page.h" +#include "vmSurface.h" + +struct child_surface { + int surface; + int type; + Point pos; +}; + +struct animation { + int nr_frames; + int current_frame; + int total_frame_time; + int frame_times[]; +}; + +struct vm_sprite { + struct sprite sp; + int surface; + int type; + Rectangle rect; + int current; + int id; + bool findable; + struct animation *anime; + struct id_pool children; +}; + +static struct id_pool pool; +static int default_layer = 200000; +static SDL_Rect dirty_rect; + +static void check_array(struct page *array) +{ + if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->array.rank != 1) + VM_ERROR("Not a flat integer array"); +} + +static void vm_sprite_dirty(struct vm_sprite *sp) +{ + scene_sprite_dirty(&sp->sp); + SDL_UnionRect(&dirty_rect, &sp->rect, &dirty_rect); +} + +static void update_animation(void) +{ + uint64_t now = SDL_GetTicks64(); + + for (int id = id_pool_get_first(&pool); id >= 0; id = id_pool_get_next(&pool, id)) { + struct vm_sprite *sp = id_pool_get(&pool, id); + if (!sp || !sp->anime) + continue; + int t = now % sp->anime->total_frame_time; + int frame; + for (frame = 0; t >= sp->anime->frame_times[frame]; frame++) + t -= sp->anime->frame_times[frame]; + if (frame == sp->anime->current_frame) + continue; + sp->anime->current_frame = frame; + vm_sprite_dirty(sp); + } +} + +static void render_surface(int surface, int type, int current, Rectangle *rect, Point *pos) +{ + struct vm_surface *sf = vm_surface_get(surface); + Texture *src = &sf->texture; + Texture *dst = gfx_main_surface(); + int sx = 0; + int sy = 0; + int dx = rect->x + (pos ? pos->x : 0); + int dy = rect->y + (pos ? pos->y : 0); + int w = pos ? src->w : rect->w; + int h = pos ? src->h : rect->h; + + if (current) { + int col = sf->w / w; + sx = current % col * w; + sy = current / col * h; + } + + switch (type) { + case 0: + gfx_copy(dst, dx, dy, src, sx, sy, w, h); + break; + case 1: + gfx_blend_amap(dst, dx, dy, src, sx, sy, w, h); + break; + case 2: + gfx_copy_sprite(dst, dx, dy, src, sx, sy, w, h, COLOR(255, 0, 255, 0)); + break; + case 3: + gfx_blend_add_satur(dst, dx, dy, src, sx, sy, w, h); + break; + default: + WARNING("unknown vmSprite type %d", type); + break; + } +} + +static void vm_sprite_render(struct sprite *_sp) +{ + struct vm_sprite *sp = (struct vm_sprite*)_sp; + if (sp->current >= 0) { + int current = sp->current + (sp->anime ? sp->anime->current_frame : 0); + render_surface(sp->surface, sp->type, current, &sp->rect, NULL); + } + + for (int id = id_pool_get_first(&sp->children); id >= 0; id = id_pool_get_next(&sp->children, id)) { + struct child_surface *child = id_pool_get(&sp->children, id); + if (!child) + continue; + render_surface(child->surface, child->type, 0, &sp->rect, &child->pos); + } +} + +static cJSON *vm_sprite_to_json(struct sprite *_sp, bool verbose) +{ + struct vm_sprite* sp = (struct vm_sprite*)_sp; + cJSON *ent, *sprite, *children; + + ent = scene_sprite_to_json(_sp, verbose); + cJSON_AddItemToObjectCS(ent, "vmSprite", sprite = cJSON_CreateObject()); + + cJSON_AddNumberToObject(sprite, "surface", sp->surface); + struct vm_surface *sf = vm_surface_get(sp->surface); + if (sf && sf->cg_no) { + cJSON_AddNumberToObject(sprite, "cg_no", sf->cg_no); + } + + cJSON_AddNumberToObject(sprite, "type", sp->type); + cJSON_AddItemToObjectCS(sprite, "rect", rectangle_to_json(&sp->rect, verbose)); + cJSON_AddNumberToObject(sprite, "current", sp->current); + + cJSON_AddItemToObjectCS(sprite, "children", children = cJSON_CreateArray()); + for (int id = id_pool_get_first(&sp->children); id >= 0; id = id_pool_get_next(&sp->children, id)) { + struct child_surface *child = id_pool_get(&sp->children, id); + if (!child) + continue; + cJSON *c; + cJSON_AddItemToArray(children, c = cJSON_CreateObject()); + cJSON_AddNumberToObject(c, "surface", child->surface); + cJSON_AddNumberToObject(c, "type", child->type); + cJSON_AddItemToObjectCS(c, "pos", point_to_json(&child->pos, verbose)); + } + + return ent; +} + +static void vm_sprite_delete(struct vm_sprite *sp) +{ + if (!sp) + return; + scene_unregister_sprite(&sp->sp); + for (int id = id_pool_get_first(&sp->children); id >= 0; id = id_pool_get_next(&sp->children, id)) { + struct child_surface *child = id_pool_get(&sp->children, id); + if (child) + free(child); + } + if (sp->anime) + free(sp->anime); + id_pool_delete(&sp->children); + free(sp); +} + +static void vmSprite_New(possibly_unused void *imainsystem) +{ + if (pool.slots) + return; // already initialized + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmSprite_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmSprite_Open(int surface, int type, int width, int height) +{ + int no = id_pool_get_unused(&pool); + struct vm_sprite *sp = xcalloc(1, sizeof(struct vm_sprite)); + id_pool_set(&pool, no, sp); + sp->sp.z = ++default_layer; + sp->sp.has_pixel = true; + sp->sp.hidden = true; + sp->sp.id = no; + sp->sp.render = vm_sprite_render; + sp->sp.to_json = vm_sprite_to_json; + sp->surface = surface; + sp->type = type; + sp->rect.w = width; + sp->rect.h = height; + sp->id = -1; + return no; +} + +static int vmSprite_Reopen(int sprite, int surface, int type, int width, int height) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return 0; + sp->surface = surface; + sp->type = type; + sp->rect.w = width; + sp->rect.h = height; + return sprite; +} + +static void vmSprite_Close(int sprite) +{ + vm_sprite_delete(id_pool_release(&pool, sprite)); +} + +static int vmSprite_Release(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmSprite_Close(i); + id_pool_delete(&pool); + return 1; +} + +static void vmSprite_ModuleFini(void) +{ + vmSprite_Release(); +} + +static int vmSprite_SetLayer(int sprite, int layer) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return 0; + scene_set_sprite_z(&sp->sp, layer); + return 1; +} + +static void vmSprite_SetPos(int sprite, int x, int y) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (sp) { + vm_sprite_dirty(sp); + sp->rect.x = x; + sp->rect.y = y; + vm_sprite_dirty(sp); + } +} + +static int vmSprite_SetCurrent(int sprite, int current) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return 0; + if (sp->current != current) { + sp->current = current; + vm_sprite_dirty(sp); + } + return 1; +} + +static int vmSprite_SetCurrentArray1(struct page *array, int current) +{ + if (!array) + return 0; + check_array(array); + + for (int i = 0; i < array->nr_vars; i++) { + vmSprite_SetCurrent(array->values[i].i, current); + } + return 1; +} + +static int vmSprite_SetCurrentArray2(struct page *sprite_array, struct page *current_array) +{ + if (!sprite_array || !current_array) + return 0; + check_array(sprite_array); + check_array(current_array); + if (sprite_array->nr_vars != current_array->nr_vars) + return 0; + for (int i = 0; i < sprite_array->nr_vars; i++) { + vmSprite_SetCurrent(sprite_array->values[i].i, current_array->values[i].i); + } + return 1; +} + +static int vmSprite_SetShow(int sprite, int show) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return 0; + scene_set_sprite_show(&sp->sp, show); + vm_sprite_dirty(sp); + return 1; +} + +static int vmSprite_SetShowArray1(struct page *array, int show) +{ + if (!array) + return 0; + check_array(array); + + for (int i = 0; i < array->nr_vars; i++) { + vmSprite_SetShow(array->values[i].i, show); + } + return 1; +} + +static int vmSprite_SetShowArray2(struct page *sprite_array, struct page *show_array) +{ + if (!sprite_array || !show_array) + return 0; + check_array(sprite_array); + check_array(show_array); + if (sprite_array->nr_vars != show_array->nr_vars) + return 0; + for (int i = 0; i < sprite_array->nr_vars; i++) { + vmSprite_SetShow(sprite_array->values[i].i, show_array->values[i].i); + } + return 1; +} + +static void vmSprite_SetRenewal(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return; + vm_sprite_dirty(sp); +} + +static void vmSprite_SetFind(int sprite, int find) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (sp) + sp->findable = !!find; +} + +static void vmSprite_SetID(int sprite, int id) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (sp) + sp->id = id; +} + +static int vmSprite_SetAnime(int sprite, int frame_s, int frame_e, struct page *array) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return 0; + check_array(array); + if (sp->anime) + free(sp->anime); + int nr_frames = array->nr_vars; + struct animation *a = xmalloc(sizeof(struct animation) + nr_frames * sizeof(int)); + a->nr_frames = nr_frames; + a->current_frame = 0; + a->total_frame_time = 0; + for (int i = 0; i < a->nr_frames; i++) { + a->total_frame_time += a->frame_times[i] = array->values[i].i; + } + sp->anime = a; + return 1; +} + +static void vmSprite_ResetAnime(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return; + free(sp->anime); + sp->anime = NULL; +} + +static int vmSprite_SetChildSurface(int sprite, int num, int surface, int type, int x, int y) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return 0; + + struct child_surface *child = id_pool_get(&sp->children, num); + if (!child) { + child = xcalloc(1, sizeof(struct child_surface)); + id_pool_set(&sp->children, num, child); + } + child->surface = surface; + child->type = type; + child->pos.x = x; + child->pos.y = y; + return 1; +} + +static int vmSprite_ResetChildSurface(int sprite, int num) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + if (!sp) + return 0; + + struct child_surface *child = id_pool_release(&sp->children, num); + if (child) + free(child); + return 1; +} + +static void vmSprite_Draw(int update) +{ + handle_events(); + update_animation(); + if (scene_is_dirty) { + scene_render(); + if (update) + gfx_swap(); + scene_is_dirty = false; + dirty_rect = RECT(0, 0, 0, 0); + } +} + +static void vmSprite_DrawEffect(int effect, int time) +{ + // XXX: This function should only apply the effect to `dirty_rect`, while + // sact_Effect applies the effect to the whole screen. In most cases it + // doesn't make a difference because (1) the effect is no-op for pixels + // where the old and new colors are the same (e.g. crossfade), or (2) the + // whole screen is dirty. In Mamanyonyo, the exception is + // EFFECT_ROTATE_OUT_CW, which must be applied to `dirty_rect` correctly. + if (effect != EFFECT_ROTATE_OUT_CW) { + sact_Effect(effect, time, 0); + return; + } + + if (SDL_RectEmpty(&dirty_rect)) + return; + uint64_t start = SDL_GetTicks64(); + Texture *screen = gfx_main_surface(); + Texture base, src; + gfx_init_texture_blank(&src, dirty_rect.w, dirty_rect.h); + gfx_copy(&src, 0, 0, screen, dirty_rect.x, dirty_rect.y, dirty_rect.w, dirty_rect.h); + scene_render(); + gfx_copy_main_surface(&base); + + uint64_t t = SDL_GetTicks64() - start; + float cx = dirty_rect.x + dirty_rect.w / 2.0f; + float cy = dirty_rect.y + dirty_rect.h / 2.0f; + while (t < time) { + float rate = (float)t / time; + + gfx_clear(); + gfx_copy(screen, 0, 0, &base, 0, 0, screen->w, screen->h); + gfx_copy_root_zoom2(screen, cx, cy, &src, src.w / 2.0f, src.h / 2.0f, rate * -360, 1.0f - rate); + gfx_swap(); + + uint64_t t2 = SDL_GetTicks64() - start; + if (t2 < t + 16) { + SDL_Delay(t + 16 - t2); + t += 16; + } else { + t = t2; + } + } + gfx_delete_texture(&base); + gfx_delete_texture(&src); +} + +static int vmSprite_AddRect(int x, int y, int width, int height) +{ + SDL_Rect r = RECT(x, y, width, height); + SDL_UnionRect(&dirty_rect, &r, &dirty_rect); + scene_dirty(); + return 1; +} + +//void vmSprite_SetSurface(int hSurface); + +static int vmSprite_FindPos(int x, int y) +{ + int found = 0; + int z = 0; + Point p = { .x = x, .y = y }; + for (int id = id_pool_get_first(&pool); id >= 0; id = id_pool_get_next(&pool, id)) { + struct vm_sprite *sp = id_pool_get(&pool, id); + if (!sp || !sp->findable) + continue; + if (!SDL_PointInRect(&p, &sp->rect)) + continue; + if (found && sp->sp.z < z) + continue; + found = id; + z = sp->sp.z; + } + return found; +} + +//int vmSprite_FindSprite(int sprite); + +static int vmSprite_GetSurface(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->surface : 0; +} + +static int vmSprite_GetType(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->type : 0; +} + +static int vmSprite_GetWidth(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->rect.w : 0; +} + +static int vmSprite_GetHeight(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->rect.h : 0; +} + +static int vmSprite_GetLayer(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->sp.z : 0; +} + +static int vmSprite_GetX(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->rect.x : 0; +} + +static int vmSprite_GetY(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->rect.y : 0; +} + +static int vmSprite_GetCurrent(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->current : 0; +} + +static int vmSprite_GetShow(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? scene_get_sprite_show(&sp->sp) : 0; +} + +//int vmSprite_GetRenewal(int sprite); + +static int vmSprite_GetFind(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->findable : 0; +} + +static int vmSprite_GetID(int sprite) +{ + struct vm_sprite *sp = id_pool_get(&pool, sprite); + return sp ? sp->id : -1; +} + +HLL_LIBRARY(vmSprite, + HLL_EXPORT(_ModuleFini, vmSprite_ModuleFini), + HLL_EXPORT(New, vmSprite_New), + HLL_EXPORT(Release, vmSprite_Release), + HLL_EXPORT(EnumHandle, vmSprite_EnumHandle), + HLL_EXPORT(Open, vmSprite_Open), + HLL_EXPORT(Reopen, vmSprite_Reopen), + HLL_EXPORT(Close, vmSprite_Close), + HLL_EXPORT(SetLayer, vmSprite_SetLayer), + HLL_EXPORT(SetPos, vmSprite_SetPos), + HLL_EXPORT(SetCurrent, vmSprite_SetCurrent), + HLL_EXPORT(SetCurrentArray1, vmSprite_SetCurrentArray1), + HLL_EXPORT(SetCurrentArray2, vmSprite_SetCurrentArray2), + HLL_EXPORT(SetShow, vmSprite_SetShow), + HLL_EXPORT(SetShowArray1, vmSprite_SetShowArray1), + HLL_EXPORT(SetShowArray2, vmSprite_SetShowArray2), + HLL_EXPORT(SetRenewal, vmSprite_SetRenewal), + HLL_EXPORT(SetFind, vmSprite_SetFind), + HLL_EXPORT(SetID, vmSprite_SetID), + HLL_EXPORT(SetAnime, vmSprite_SetAnime), + HLL_EXPORT(ResetAnime, vmSprite_ResetAnime), + HLL_EXPORT(SetChildSurface, vmSprite_SetChildSurface), + HLL_EXPORT(ResetChildSurface, vmSprite_ResetChildSurface), + HLL_EXPORT(Draw, vmSprite_Draw), + HLL_EXPORT(DrawEffect, vmSprite_DrawEffect), + HLL_EXPORT(AddRect, vmSprite_AddRect), + HLL_TODO_EXPORT(SetSurface, vmSprite_SetSurface), + HLL_EXPORT(FindPos, vmSprite_FindPos), + HLL_TODO_EXPORT(FindSprite, vmSprite_FindSprite), + HLL_EXPORT(GetSurface, vmSprite_GetSurface), + HLL_EXPORT(GetType, vmSprite_GetType), + HLL_EXPORT(GetWidth, vmSprite_GetWidth), + HLL_EXPORT(GetHeight, vmSprite_GetHeight), + HLL_EXPORT(GetLayer, vmSprite_GetLayer), + HLL_EXPORT(GetX, vmSprite_GetX), + HLL_EXPORT(GetY, vmSprite_GetY), + HLL_EXPORT(GetCurrent, vmSprite_GetCurrent), + HLL_EXPORT(GetShow, vmSprite_GetShow), + HLL_TODO_EXPORT(GetRenewal, vmSprite_GetRenewal), + HLL_EXPORT(GetFind, vmSprite_GetFind), + HLL_EXPORT(GetID, vmSprite_GetID) + ); diff --git a/src/hll/vmString.c b/src/hll/vmString.c new file mode 100644 index 0000000..b8f3287 --- /dev/null +++ b/src/hll/vmString.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include + +#include "system4/string.h" +#include "system4/utfsjis.h" + +#include "hll.h" + +static int vmString_GetLength(struct string *string) +{ + return sjis_count_char(string->text); +} + +static int vmString_GetLengthA(struct string *string) +{ + return strlen(string->text); +} + +static struct string *format_int(int v, int figures, bool zero_pad, bool zenkaku) +{ + char buf[32]; + int_to_cstr(buf, sizeof(buf), v, figures, zero_pad, zenkaku); + return cstr_to_string(buf); +} + +static struct string *vmString_IntToString(int num) +{ + return format_int(num, 0, false, true); +} + +struct string *vmString_IntToStringA(int num) +{ + return format_int(num, 0, false, false); +} + +static struct string *vmString_IntToStringEx(int num, int figure, int zero) +{ + return format_int(num, figure, zero, true); +} + +static struct string *vmString_IntToStringExA(int num, int figure, int zero) +{ + return format_int(num, figure, zero, false); +} + +//int vmString_StringToInt(struct string *pIString); +//struct string *vmString_FloatToString(float fNum); +//struct string *vmString_FloatToStringA(float fNum); +//float vmString_StringToFloat(struct string *pIString); +//struct string *vmString_GetString(struct string *pIString, int nIndex, int nLength); +//struct string *vmString_CutTag(struct string *pIString); +//void vmString_TransLower(struct string **pIString); +//void vmString_TransUpper(struct string **pIString); +//void vmString_Convert(struct string **pIDString, struct string *pISString, struct string *pICString); + +HLL_LIBRARY(vmString, + HLL_EXPORT(GetLength, vmString_GetLength), + HLL_EXPORT(GetLengthA, vmString_GetLengthA), + HLL_EXPORT(IntToString, vmString_IntToString), + HLL_EXPORT(IntToStringA, vmString_IntToStringA), + HLL_EXPORT(IntToStringEx, vmString_IntToStringEx), + HLL_EXPORT(IntToStringExA, vmString_IntToStringExA), + HLL_TODO_EXPORT(StringToInt, vmString_StringToInt), + HLL_TODO_EXPORT(FloatToString, vmString_FloatToString), + HLL_TODO_EXPORT(FloatToStringA, vmString_FloatToStringA), + HLL_TODO_EXPORT(StringToFloat, vmString_StringToFloat), + HLL_TODO_EXPORT(GetString, vmString_GetString), + HLL_TODO_EXPORT(CutTag, vmString_CutTag), + HLL_TODO_EXPORT(TransLower, vmString_TransLower), + HLL_TODO_EXPORT(TransUpper, vmString_TransUpper), + HLL_TODO_EXPORT(Convert, vmString_Convert) + ); diff --git a/src/hll/vmSurface.c b/src/hll/vmSurface.c new file mode 100644 index 0000000..67fe5b8 --- /dev/null +++ b/src/hll/vmSurface.c @@ -0,0 +1,152 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "hll.h" +#include "id_pool.h" +#include "vmSurface.h" + +static struct id_pool pool; + +struct vm_surface *vm_surface_create(int width, int height) +{ + int no = id_pool_get_unused(&pool); + struct vm_surface *sf = xcalloc(1, sizeof(struct vm_surface)); + id_pool_set(&pool, no, sf); + sf->w = width; + sf->h = height; + sf->has_pixel = true; + sf->has_alpha = true; + sf->no = no; + return sf; +} + +struct vm_surface *vm_surface_get(int no) +{ + return id_pool_get(&pool, no); +} + +void vm_surface_delete(int no) +{ + struct vm_surface *sf = id_pool_release(&pool, no); + if (sf) { + gfx_delete_texture(&sf->texture); + free(sf); + } +} + +int vm_surface_get_main_surface(void) +{ + return ID_POOL_HANDLE_BASE; +} + +static void vmSurface_New(void) +{ + if (pool.slots) + return; // already initialized + gfx_init(); + id_pool_init(&pool, ID_POOL_HANDLE_BASE); + + // create main surface + Texture *t = gfx_main_surface(); + struct vm_surface *sf = vm_surface_create(t->w, t->h); + sf->texture = *t; // XXX: textures normally shouldn't be copied like this... + assert(sf->no == ID_POOL_HANDLE_BASE); +} + +static int vmSurface_Release(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vm_surface_delete(i); + id_pool_delete(&pool); + return 1; +} + +static void vmSurface_ModuleFini(void) +{ + vmSurface_Release(); +} + +static int vmSurface_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmSurface_Create(int width, int height, possibly_unused int bpp) +{ + struct vm_surface *sf = vm_surface_create(width, height); + gfx_init_texture_rgba(&sf->texture, sf->w, sf->h, (SDL_Color){0, 0, 0, 0}); + return sf->no; +} + +static int vmSurface_CreatePixelMap(int width, int height, possibly_unused int bpp) +{ + struct vm_surface *sf = vm_surface_create(width, height); + gfx_init_texture_rgba(&sf->texture, sf->w, sf->h, (SDL_Color){0, 0, 0, 255}); + sf->has_alpha = false; + return sf->no; +} + +static int vmSurface_CreateAlphaMap(int width, int height) +{ + struct vm_surface *sf = vm_surface_create(width, height); + gfx_init_texture_rgba(&sf->texture, sf->w, sf->h, (SDL_Color){0, 0, 0, 255}); + sf->has_pixel = false; + return sf->no; +} + +static int vmSurface_GetWidth(int surface) +{ + struct vm_surface *sf = id_pool_get(&pool, surface); + return sf ? sf->w : 0; +} + +static int vmSurface_GetHeight(int surface) +{ + struct vm_surface *sf = id_pool_get(&pool, surface); + return sf ? sf->h : 0; +} + +//int vmSurface_GetBpp(int surface); + +static int vmSurface_ExistPixel(int surface) +{ + struct vm_surface *sf = id_pool_get(&pool, surface); + return sf && sf->has_pixel; +} + +static int vmSurface_ExistAlpha(int surface) +{ + struct vm_surface *sf = id_pool_get(&pool, surface); + return sf && sf->has_alpha; +} + +HLL_LIBRARY(vmSurface, + HLL_EXPORT(_ModuleFini, vmSurface_ModuleFini), + HLL_EXPORT(New, vmSurface_New), + HLL_EXPORT(Release, vmSurface_Release), + HLL_EXPORT(EnumHandle, vmSurface_EnumHandle), + HLL_EXPORT(Create, vmSurface_Create), + HLL_EXPORT(CreatePixelMap, vmSurface_CreatePixelMap), + HLL_EXPORT(CreateAlphaMap, vmSurface_CreateAlphaMap), + HLL_EXPORT(Delete, vm_surface_delete), + HLL_EXPORT(GetWidth, vmSurface_GetWidth), + HLL_EXPORT(GetHeight, vmSurface_GetHeight), + HLL_TODO_EXPORT(GetBpp, vmSurface_GetBpp), + HLL_EXPORT(ExistPixel, vmSurface_ExistPixel), + HLL_EXPORT(ExistAlpha, vmSurface_ExistAlpha) + ); diff --git a/src/hll/vmSurface.h b/src/hll/vmSurface.h new file mode 100644 index 0000000..069f233 --- /dev/null +++ b/src/hll/vmSurface.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef SYSTEM4_HLL_VMSURFACE_H +#define SYSTEM4_HLL_VMSURFACE_H + +#include "gfx/gfx.h" + +struct vm_surface { + struct texture texture; + int no; + int w; + int h; + bool has_pixel; + bool has_alpha; + int cg_no; +}; + +struct vm_surface *vm_surface_create(int width, int height); +struct vm_surface *vm_surface_get(int no); +void vm_surface_delete(int no); +int vm_surface_get_main_surface(void); + +#endif /* SYSTEM4_HLL_VMSURFACE_H */ diff --git a/src/hll/vmSystem.c b/src/hll/vmSystem.c new file mode 100644 index 0000000..d05a440 --- /dev/null +++ b/src/hll/vmSystem.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include + +#include "system4/string.h" + +#include "hll.h" +#include "vm/page.h" + +HLL_QUIET_UNIMPLEMENTED( , void, vmSystem, Init, void *imainsystem); + +void vmSystem_CurrentTime(struct page **page) +{ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) < 0) { + WARNING("clock_gettime failed: %s", strerror(errno)); + return; + } + struct tm *tm = localtime(&ts.tv_sec); + if (!tm) { + WARNING("localtime failed: %s", strerror(errno)); + return; + } + + union vm_value *date = (*page)->values; + date[0].i = tm->tm_year + 1900; + date[1].i = tm->tm_mon + 1; + date[2].i = tm->tm_mday; + date[3].i = tm->tm_hour; + date[4].i = tm->tm_min; + date[5].i = tm->tm_sec; + date[6].i = tm->tm_wday; +} + +//void vmSystem_Reset(void); +//void vmSystem_Shutdown(void); + +static int vmSystem_OpenWeb(struct string *url) +{ + return SDL_OpenURL(url->text) == 0; +} + +HLL_WARN_UNIMPLEMENTED(0, int, vmSystem, AddURLMenu, struct string *title, struct string *url); + +HLL_LIBRARY(vmSystem, + HLL_EXPORT(Init, vmSystem_Init), + HLL_EXPORT(CurrentTime, vmSystem_CurrentTime), + HLL_TODO_EXPORT(Reset, vmSystem_Reset), + HLL_TODO_EXPORT(Shutdown, vmSystem_Shutdown), + HLL_EXPORT(OpenWeb, vmSystem_OpenWeb), + HLL_EXPORT(AddURLMenu, vmSystem_AddURLMenu) + ); diff --git a/src/hll/vmTimer.c b/src/hll/vmTimer.c new file mode 100644 index 0000000..d2586b7 --- /dev/null +++ b/src/hll/vmTimer.c @@ -0,0 +1,103 @@ +/* Copyright (C) 2024 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "hll.h" +#include "id_pool.h" + +struct vm_timer { + uint64_t origin; +}; + +static struct id_pool pool; + +static void vmTimer_Init(possibly_unused void *imainsystem) +{ + if (pool.slots) + return; // already initialized + id_pool_init(&pool, ID_POOL_HANDLE_BASE); +} + +static int vmTimer_EnumHandle(void) +{ + return id_pool_count(&pool); +} + +static int vmTimer_Open(void) +{ + int handle = id_pool_get_unused(&pool); + struct vm_timer *timer = xcalloc(1, sizeof(struct vm_timer)); + id_pool_set(&pool, handle, timer); + return handle; +} + +static void vmTimer_Close(int handle) +{ + struct vm_timer *timer = id_pool_release(&pool, handle); + if (timer) + free(timer); +} + +static void vmTimer_ModuleFini(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + vmTimer_Close(i); + id_pool_delete(&pool); +} + +static void vmTimer_Set(int handle, int time) +{ + struct vm_timer *timer = id_pool_get(&pool, handle); + if (!timer) + return; + timer->origin = SDL_GetTicks64() - time; +} + +static int vmTimer_Get(int handle) +{ + struct vm_timer *timer = id_pool_get(&pool, handle); + if (!timer) + return 0; + return SDL_GetTicks64() - timer->origin; +} + +static void vmTimer_Wait(int time) +{ + SDL_Delay(time); +} + +static void vmTimer_Pass(int handle, int time) +{ + struct vm_timer *timer = id_pool_get(&pool, handle); + if (!timer) + return; + int ms = timer->origin + time - SDL_GetTicks64(); + if (ms > 0) + SDL_Delay(ms); +} + +HLL_LIBRARY(vmTimer, + HLL_EXPORT(_ModuleFini, vmTimer_ModuleFini), + HLL_EXPORT(Init, vmTimer_Init), + HLL_EXPORT(EnumHandle, vmTimer_EnumHandle), + HLL_EXPORT(Open, vmTimer_Open), + HLL_EXPORT(Close, vmTimer_Close), + HLL_EXPORT(Set, vmTimer_Set), + HLL_EXPORT(Get, vmTimer_Get), + HLL_EXPORT(Wait, vmTimer_Wait), + HLL_EXPORT(Pass, vmTimer_Pass) + ); diff --git a/src/id_pool.c b/src/id_pool.c index be43f30..32627f1 100644 --- a/src/id_pool.c +++ b/src/id_pool.c @@ -15,6 +15,7 @@ */ #include +#include #include "system4.h" #include "id_pool.h" @@ -26,10 +27,18 @@ #define ID_POOL_INIT_SLOTS 32 #define ID_POOL_ALLOC_HEADROOM 256 -void id_pool_init(struct id_pool *pool) +void id_pool_init(struct id_pool *pool, int base) { pool->slots = xcalloc(ID_POOL_INIT_SLOTS, sizeof(void*)); pool->nr_slots = ID_POOL_INIT_SLOTS; + pool->base = base; +} + +void id_pool_delete(struct id_pool *pool) +{ + free(pool->slots); + pool->slots = NULL; + pool->nr_slots = 0; } static void id_pool_realloc(struct id_pool *pool, int new_size) @@ -38,26 +47,60 @@ static void id_pool_realloc(struct id_pool *pool, int new_size) pool->nr_slots = new_size; } -void id_pool_release(struct id_pool *pool, int id) +void *id_pool_release(struct id_pool *pool, int id) { - if (pool->slots[id]) - pool->slots[id] = NULL; + id -= pool->base; + if (id < 0 || id >= pool->nr_slots) + return NULL; + void *data = pool->slots[id]; + pool->slots[id] = NULL; + return data; +} + +int id_pool_count(struct id_pool *pool) +{ + int count = 0; + for (int i = 0; i < pool->nr_slots; i++) { + if (pool->slots[i]) + count++; + } + return count; } int id_pool_get_unused(struct id_pool *pool) { for (int i = 0; i < pool->nr_slots; i++) { if (!pool->slots[i]) - return i; + return pool->base + i; } int id = pool->nr_slots; id_pool_realloc(pool, id + ID_POOL_ALLOC_HEADROOM); - return id; + return pool->base + id; +} + +int id_pool_get_first(struct id_pool *pool) +{ + for (int i = 0; i < pool->nr_slots; i++) { + if (pool->slots[i]) + return pool->base + i; + } + return -1; +} + +int id_pool_get_next(struct id_pool *pool, int id) +{ + id -= pool->base; + for (int i = id + 1; i < pool->nr_slots; i++) { + if (pool->slots[i]) + return pool->base + i; + } + return -1; } void *id_pool_get(struct id_pool *pool, int id) { + id -= pool->base; if (id < 0 || id >= pool->nr_slots) return NULL; return pool->slots[id]; @@ -65,6 +108,7 @@ void *id_pool_get(struct id_pool *pool, int id) void *id_pool_set(struct id_pool *pool, int id, void *data) { + id -= pool->base; assert(id >= 0); if (id >= pool->nr_slots) id_pool_realloc(pool, id + ID_POOL_ALLOC_HEADROOM); diff --git a/src/meson.build b/src/meson.build index 354a7ef..84021f7 100644 --- a/src/meson.build +++ b/src/meson.build @@ -103,6 +103,8 @@ xsystem4 = [version_h, 'hll/LoadCG.c', 'hll/MainEXFile.c', 'hll/MainSurface.c', + 'hll/MamanyoDemo.c', + 'hll/MamanyoSDemo.c', 'hll/MarmotModelEngine.c', 'hll/Math.c', 'hll/MapLoader.c', @@ -127,6 +129,29 @@ xsystem4 = [version_h, 'hll/SystemServiceEx.c', 'hll/Timer.c', 'hll/Toushin3Loader.c', + 'hll/vmAnime.c', + 'hll/vmArray.c', + 'hll/vmCG.c', + 'hll/vmChrLoader.c', + 'hll/vmCursor.c', + 'hll/vmDialog.c', + 'hll/vmDrawGauge.c', + 'hll/vmDrawMsg.c', + 'hll/vmDrawNumber.c', + 'hll/vmFile.c', + 'hll/vmGraph.c', + 'hll/vmGraphQuake.c', + 'hll/vmKey.c', + 'hll/vmMapLoader.c', + 'hll/vmMsgLog.c', + 'hll/vmMsgSkip.c', + 'hll/vmMusic.c', + 'hll/vmSound.c', + 'hll/vmSprite.c', + 'hll/vmString.c', + 'hll/vmSurface.c', + 'hll/vmSystem.c', + 'hll/vmTimer.c', 'hll/VSFile.c', ]