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', ]