diff --git a/src/hll/CharSpriteManager.c b/src/hll/CharSpriteManager.c new file mode 100644 index 0000000..93ae02b --- /dev/null +++ b/src/hll/CharSpriteManager.c @@ -0,0 +1,242 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * 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.h" +#include "system4/string.h" +#include "system4/utfsjis.h" +#include "vm/heap.h" +#include "vm/page.h" +#include "sprite.h" +#include "CharSpriteManager.h" + +/* + * NOTE: This is not a library on it's own, but rather part of + * StoatSpriteEngine/ChipmunkSpriteEngine. + */ + +struct charsprite { + struct sact_sprite sp; + // NOTE: even though we only render a single character, we need to store an + // arbitrary string because CharSprite_GetChar returns it. + struct string *ch; + struct text_metrics tm; +}; + +static struct { + unsigned size; + struct charsprite **sprites; + unsigned nr_free; + int *free; +} chars = {0}; + +static void grow_chars(unsigned new_size) { + assert(new_size > chars.size); + chars.sprites = xrealloc_array(chars.sprites, chars.size, new_size, sizeof(struct charsprite*)); + chars.free = xrealloc_array(chars.free, chars.size, new_size, sizeof(int)); + + for (unsigned i = chars.size; i < new_size; i++) { + chars.free[chars.nr_free++] = i; + } + + chars.size = new_size; +} + +static int get_handle(void) +{ + if (!chars.nr_free) { + grow_chars(chars.size ? chars.size*2 : 256); + } + return chars.free[--chars.nr_free]; +} + +static bool handle_valid(int handle) +{ + return handle >= 0 && (unsigned)handle < chars.size && chars.sprites[handle]; +} + +static void check_handle(int handle) +{ + if (!handle_valid(handle)) + VM_ERROR("Invalid CharSprite handle: %d", handle); +} + +static struct charsprite *charsprite_get(int handle) +{ + check_handle(handle); + return chars.sprites[handle]; +} + +static bool charsprite_allocated(struct charsprite *cs) +{ + return cs->ch != NULL; +} + +int CharSpriteManager_CreateHandle(void) +{ + int handle = get_handle(); + assert(!chars.sprites[handle]); + chars.sprites[handle] = xcalloc(1, sizeof(struct charsprite)); + return handle; +} + +bool CharSpriteManager_ReleaseHandle(int handle) +{ + if (!handle_valid(handle)) + return false; + + sprite_free(&chars.sprites[handle]->sp); + if (chars.sprites[handle]->ch) { + free_string(chars.sprites[handle]->ch); + } + free(chars.sprites[handle]); + chars.sprites[handle] = NULL; + chars.free[chars.nr_free++] = handle; + return true; +} + +void CharSpriteManager_Clear(void) +{ + for (unsigned i = 0; i < chars.size; i++) { + CharSpriteManager_ReleaseHandle(i); + } +} + +//static void CharSpriteManager_Rebuild(void); +//static bool CharSpriteManager_Save(struct page **iarray); +//static bool CharSpriteManager_Load(struct page **iarray); + +void CharSprite_Release(int handle) +{ + struct charsprite *sp = charsprite_get(handle); + sprite_free(&sp->sp); +} + +static void CASColor_to_SDL_Color(SDL_Color *color, int page_no) +{ + struct page *page = heap_get_page(page_no); + assert(page); + assert(page->nr_vars == 4); + color->r = page->values[0].i; + color->g = page->values[1].i; + color->b = page->values[2].i; + color->a = page->values[3].i; +} + +static void CASCharSpriteProperty_to_text_metrics(struct text_metrics *tm, struct page *page) +{ + assert(page); + assert(page->nr_vars == 6); + + tm->face = page->values[0].i; + tm->size = page->values[1].i; + CASColor_to_SDL_Color(&tm->color, page->values[2].i); + //tm->weight = page->values[3].f; + tm->weight = FW_NORMAL; + tm->outline_left = page->values[4].f; + tm->outline_up = tm->outline_left; + tm->outline_right = tm->outline_left; + tm->outline_down = tm->outline_left; + CASColor_to_SDL_Color(&tm->outline_color, page->values[5].i); +} + +static int extract_sjis_char(char *src, char *dst) +{ + if (SJIS_2BYTE(*src)) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = '\0'; + return 2; + } + dst[0] = src[0]; + dst[1] = '\0'; + return 1; +} + +void CharSprite_SetChar(int handle, struct string **s, struct page **property) +{ + struct charsprite *sp = charsprite_get(handle); + CASCharSpriteProperty_to_text_metrics(&sp->tm, *property); + + if (charsprite_allocated(sp)) { + sprite_free(&sp->sp); + } + if (sp->ch) { + free_string(sp->ch); + sp->ch = NULL; + } + if (!(*s)->size) { + return; + } + + sp->ch = string_ref(*s); + + char ch[3]; + extract_sjis_char((*s)->text, ch); + + int w = sp->tm.size; + int h = sp->tm.size; + if (isascii(ch[0])) + w /= 2; + + sprite_init(&sp->sp, w, h, 0, 0, 0, 0); + sprite_get_texture(&sp->sp); // XXX: force initialization of texture + gfx_render_text(&sp->sp.texture, (Point) { .x=0, .y = 0 }, ch, &sp->tm, 0); + sprite_dirty(&sp->sp); +} + +void CharSprite_SetPos(int handle, int x, int y) +{ + struct charsprite *sp = charsprite_get(handle); + sprite_set_pos(&sp->sp, x, y); +} + +void CharSprite_SetZ(int handle, int z) +{ + struct charsprite *sp = charsprite_get(handle); + sprite_set_z(&sp->sp, z); +} + +void CharSprite_SetAlphaRate(int handle, int rate) +{ + struct charsprite *sp = charsprite_get(handle); + sprite_set_blend_rate(&sp->sp, rate); +} + +void CharSprite_SetShow(int handle, bool show) +{ + struct charsprite *sp = charsprite_get(handle); + sprite_set_show(&sp->sp, show); +} + +void CharSprite_GetChar(int handle, struct string **ch) +{ + struct charsprite *sp = charsprite_get(handle); + if (*ch) + free_string(*ch); + if (sp->ch) + *ch = string_ref(sp->ch); + else + *ch = string_ref(&EMPTY_STRING); +} + +int CharSprite_GetAlphaRate(int handle) +{ + struct charsprite *sp = charsprite_get(handle); + return sprite_get_blend_rate(&sp->sp); +} diff --git a/src/hll/CharSpriteManager.h b/src/hll/CharSpriteManager.h new file mode 100644 index 0000000..3ce8e95 --- /dev/null +++ b/src/hll/CharSpriteManager.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * 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_CHARSPRITE_MANAGER_H +#define SYSTEM4_HLL_CHARSPRITE_MANAGER_H + +#include + +struct page; +struct string; + +int CharSpriteManager_CreateHandle(void); +bool CharSpriteManager_ReleaseHandle(int handle); +void CharSpriteManager_Clear(void); +void CharSpriteManager_Rebuild(void); +bool CharSpriteManager_Save(struct page **iarray); +bool CharSpriteManager_Load(struct page **iarray); +void CharSprite_Release(int nHandle); +void CharSprite_SetChar(int handle, struct string **s, struct page **property); +void CharSprite_SetPos(int handle, int x, int y); +void CharSprite_SetZ(int handle, int z); +void CharSprite_SetAlphaRate(int handle, int rate); +void CharSprite_SetShow(int handle, bool show); +void CharSprite_GetChar(int handle, struct string **ch); +int CharSprite_GetAlphaRate(int handle); + +#endif /* SYSTEM4_HLL_CHARSPRITE_MANAGER_H */ diff --git a/src/hll/StoatSpriteEngine.c b/src/hll/StoatSpriteEngine.c index 53a0a7f..cd1d154 100644 --- a/src/hll/StoatSpriteEngine.c +++ b/src/hll/StoatSpriteEngine.c @@ -35,6 +35,7 @@ #include "xsystem4.h" #include "sact.h" #include "AnteaterADVEngine.h" +#include "CharSpriteManager.h" HLL_WARN_UNIMPLEMENTED( , void, StoatSpriteEngine, JoypadQuake_Set, int num, int type, int magnitude); HLL_WARN_UNIMPLEMENTED(1, int, StoatSpriteEngine, Music_SetLoopCount, int ch, int count); @@ -553,19 +554,6 @@ HLL_WARN_UNIMPLEMENTED(0, bool, StoatSpriteEngine, SYSTEM_GetInvalidateFrameSkip //void StoatSpriteEngine_ADVSceneKeeper_Clear(void); //bool StoatSpriteEngine_ADVSceneKeeper_Save(ref array@int pIVMArray); //bool StoatSpriteEngine_ADVSceneKeeper_Load(ref array@int pIVMArray); -//void StoatSpriteEngine_ADVLogList_Clear(void); -//void StoatSpriteEngine_ADVLogList_AddText(ref string pIText); -//void StoatSpriteEngine_ADVLogList_AddNewLine(void); -//void StoatSpriteEngine_ADVLogList_AddNewPage(void); -//void StoatSpriteEngine_ADVLogList_AddVoice(int nVoiceNumber); -//void StoatSpriteEngine_ADVLogList_SetEnable(bool bEnable); -//bool StoatSpriteEngine_ADVLogList_IsEnable(void); -//int StoatSpriteEngine_ADVLogList_GetNumofADVLog(void); -//int StoatSpriteEngine_ADVLogList_GetNumofADVLogText(int nADVLog); -//void StoatSpriteEngine_ADVLogList_GetADVLogText(int nADVLog, int nText, ref string pIText); -//int StoatSpriteEngine_ADVLogList_GetADVLogVoice(int nADVLog); -//bool StoatSpriteEngine_ADVLogList_Save(ref array@int pIVMArray); -//bool StoatSpriteEngine_ADVLogList_Load(ref array@int pIVMArray); HLL_LIBRARY(StoatSpriteEngine, HLL_EXPORT(_ModuleFini, StoatSpriteEngine_ModuleFini), @@ -765,6 +753,20 @@ HLL_LIBRARY(StoatSpriteEngine, HLL_EXPORT(MultiSprite_Rebuild, StoatSpriteEngine_MultiSprite_Rebuild), HLL_EXPORT(MultiSprite_Encode, StoatSpriteEngine_MultiSprite_Encode), HLL_EXPORT(MultiSprite_Decode, StoatSpriteEngine_MultiSprite_Decode), + HLL_EXPORT(CharSpriteManager_CreateHandle, CharSpriteManager_CreateHandle), + HLL_EXPORT(CharSpriteManager_ReleaseHandle, CharSpriteManager_ReleaseHandle), + HLL_EXPORT(CharSpriteManager_Clear, CharSpriteManager_Clear), + HLL_TODO_EXPORT(CharSpriteManager_Rebuild, CharSpriteManager_Rebuild), + HLL_TODO_EXPORT(CharSpriteManager_Save, CharSpriteManager_Save), + HLL_TODO_EXPORT(CharSpriteManager_Load, CharSpriteManager_Load), + HLL_EXPORT(CharSprite_Release, CharSprite_Release), + HLL_EXPORT(CharSprite_SetChar, CharSprite_SetChar), + HLL_EXPORT(CharSprite_SetPos, CharSprite_SetPos), + HLL_EXPORT(CharSprite_SetZ, CharSprite_SetZ), + HLL_EXPORT(CharSprite_SetAlphaRate, CharSprite_SetAlphaRate), + HLL_EXPORT(CharSprite_SetShow, CharSprite_SetShow), + HLL_EXPORT(CharSprite_GetChar, CharSprite_GetChar), + HLL_EXPORT(CharSprite_GetAlphaRate, CharSprite_GetAlphaRate), HLL_EXPORT(SYSTEM_IsResetOnce, StoatSpriteEngine_SYSTEM_IsResetOnce), HLL_EXPORT(SYSTEM_SetConfigOverFrameRateSleep, StoatSpriteEngine_SYSTEM_SetConfigOverFrameRateSleep), HLL_EXPORT(SYSTEM_GetConfigOverFrameRateSleep, StoatSpriteEngine_SYSTEM_GetConfigOverFrameRateSleep), diff --git a/src/meson.build b/src/meson.build index 5443450..a26a364 100644 --- a/src/meson.build +++ b/src/meson.build @@ -26,6 +26,7 @@ xsystem4 = ['audio.c', 'hll/AnteaterADVEngine.c', 'hll/BanMisc.c', 'hll/Bitarray.c', + 'hll/CharSpriteManager.c', 'hll/Confirm.c', 'hll/Confirm2.c', 'hll/CrayfishLogViewer.c', diff --git a/src/sprite.c b/src/sprite.c index 2c0ae8d..ade08a5 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -69,6 +69,7 @@ void sprite_free(struct sact_sprite *sp) sprite_unregister(sp); gfx_delete_texture(&sp->texture); gfx_delete_texture(&sp->text.texture); + memset(sp, 0, sizeof(struct sact_sprite)); } void sprite_render_scene(void)