mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-10 16:28:21 +03:00
Implement CharSpriteMangager_{Rebuild,Save,Load}
This commit is contained in:
+237
-36
@@ -24,6 +24,7 @@
|
||||
#include "vm/page.h"
|
||||
#include "sprite.h"
|
||||
#include "CharSpriteManager.h"
|
||||
#include "iarray.h"
|
||||
|
||||
/*
|
||||
* NOTE: This is not a library on it's own, but rather part of
|
||||
@@ -36,14 +37,25 @@ struct charsprite {
|
||||
// arbitrary string because CharSprite_GetChar returns it.
|
||||
struct string *ch;
|
||||
struct text_metrics tm;
|
||||
// NOTE: this is needed because we have to hide all sprites after loading
|
||||
// regardless of their original visibility. When Rebuild is called,
|
||||
// this value is used to correctly set the visibility.
|
||||
bool show;
|
||||
};
|
||||
|
||||
static struct {
|
||||
struct charsprite_manager {
|
||||
unsigned size;
|
||||
struct charsprite **sprites;
|
||||
unsigned nr_free;
|
||||
int *free;
|
||||
} chars = {0};
|
||||
};
|
||||
|
||||
static struct charsprite_manager chars = {0};
|
||||
|
||||
// XXX: after CharSpriteManager_Load, CharSpriteManager_Rebuild must be called to
|
||||
// make the loaded data visible. It is stored here until then.
|
||||
static struct charsprite_manager load_chars = {0};
|
||||
static bool loaded = false;
|
||||
|
||||
static void grow_chars(unsigned new_size) {
|
||||
assert(new_size > chars.size);
|
||||
@@ -95,21 +107,37 @@ int CharSpriteManager_CreateHandle(void)
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void charsprite_free(struct charsprite *cs)
|
||||
{
|
||||
sprite_free(&cs->sp);
|
||||
if (cs->ch) {
|
||||
free_string(cs->ch);
|
||||
}
|
||||
free(cs);
|
||||
}
|
||||
|
||||
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]);
|
||||
charsprite_free(chars.sprites[handle]);
|
||||
chars.sprites[handle] = NULL;
|
||||
chars.free[chars.nr_free++] = handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void charsprite_manager_free(struct charsprite_manager *csm)
|
||||
{
|
||||
for (unsigned i = 0; i < csm->size; i++) {
|
||||
if (csm->sprites[i])
|
||||
charsprite_free(csm->sprites[i]);
|
||||
}
|
||||
free(csm->sprites);
|
||||
free(csm->free);
|
||||
memset(csm, 0, sizeof(*csm));
|
||||
}
|
||||
|
||||
void CharSpriteManager_Clear(void)
|
||||
{
|
||||
for (unsigned i = 0; i < chars.size; i++) {
|
||||
@@ -117,9 +145,207 @@ void CharSpriteManager_Clear(void)
|
||||
}
|
||||
}
|
||||
|
||||
//static void CharSpriteManager_Rebuild(void);
|
||||
//static bool CharSpriteManager_Save(struct page **iarray);
|
||||
//static bool CharSpriteManager_Load(struct page **iarray);
|
||||
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;
|
||||
}
|
||||
|
||||
static void charsprite_render(struct charsprite *cs)
|
||||
{
|
||||
char ch[3];
|
||||
extract_sjis_char(cs->ch->text, ch);
|
||||
|
||||
int w = cs->tm.size;
|
||||
int h = cs->tm.size;
|
||||
if (isascii(ch[0]))
|
||||
w /= 2;
|
||||
|
||||
sprite_init(&cs->sp, w, h, 0, 0, 0, 0);
|
||||
sprite_get_texture(&cs->sp); // XXX: force initialization of texture
|
||||
gfx_render_text(&cs->sp.texture, (Point) { .x=0, .y = 0 }, ch, &cs->tm, 0);
|
||||
sprite_dirty(&cs->sp);
|
||||
|
||||
}
|
||||
|
||||
void CharSpriteManager_Rebuild(void)
|
||||
{
|
||||
if (!loaded)
|
||||
return;
|
||||
|
||||
charsprite_manager_free(&chars);
|
||||
chars = load_chars;
|
||||
|
||||
// reset visibility
|
||||
for (unsigned i = 0; i < chars.size; i++) {
|
||||
if (!chars.sprites[i])
|
||||
continue;
|
||||
charsprite_render(chars.sprites[i]);
|
||||
sprite_set_show(&chars.sprites[i]->sp, chars.sprites[i]->show);
|
||||
}
|
||||
|
||||
memset(&load_chars, 0, sizeof(load_chars));
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
bool CharSpriteManager_Save(struct page **iarray)
|
||||
{
|
||||
// 'C'
|
||||
// 'S'
|
||||
// 'M'
|
||||
// 0x0
|
||||
// 0x0
|
||||
// 0x1 <- nr handles (NOT necessary the length of the following list)
|
||||
// 0x1 <- ???
|
||||
// 0x67 <- 'C' (char text)
|
||||
// 0 <- '\0'
|
||||
// 0 <- m_nType
|
||||
// 64 <- m_nSize
|
||||
// ...
|
||||
// 0 <- x
|
||||
// 0 <- y
|
||||
// 0 <- z
|
||||
// 255 <- alpha rate
|
||||
// 1 <- show
|
||||
// 2000 <- handle + 2000
|
||||
|
||||
struct iarray_writer w;
|
||||
iarray_init_writer(&w, "CSM");
|
||||
iarray_write(&w, 0); // version?
|
||||
iarray_write(&w, chars.size);
|
||||
|
||||
for (unsigned i = 0; i < chars.size; i++) {
|
||||
if (!chars.sprites[i])
|
||||
continue;
|
||||
|
||||
struct charsprite *s = chars.sprites[i];
|
||||
iarray_write(&w, 1); // ???
|
||||
iarray_write_string(&w, s->ch);
|
||||
iarray_write(&w, s->tm.face);
|
||||
iarray_write(&w, s->tm.size);
|
||||
iarray_write(&w, s->tm.color.r);
|
||||
iarray_write(&w, s->tm.color.g);
|
||||
iarray_write(&w, s->tm.color.b);
|
||||
iarray_write(&w, s->tm.color.a);
|
||||
//iarray_write_float(&w, s->tm.weight);
|
||||
iarray_write_float(&w, 1.0);
|
||||
iarray_write_float(&w, s->tm.outline_left);
|
||||
iarray_write(&w, s->tm.outline_color.r);
|
||||
iarray_write(&w, s->tm.outline_color.g);
|
||||
iarray_write(&w, s->tm.outline_color.b);
|
||||
iarray_write(&w, s->tm.outline_color.a);
|
||||
iarray_write(&w, sprite_get_pos_x(&s->sp));
|
||||
iarray_write(&w, sprite_get_pos_y(&s->sp));
|
||||
iarray_write(&w, sprite_get_z(&s->sp));
|
||||
iarray_write(&w, sprite_get_blend_rate(&s->sp));
|
||||
iarray_write(&w, sprite_get_show(&s->sp));
|
||||
iarray_write(&w, 2000 + i);
|
||||
|
||||
// NOTE: Allocated but uninitialized handles are saved with a
|
||||
// handle of -1. These persist even after loading and
|
||||
// re-saving.
|
||||
// I've haven't implemented this as there's no way to know
|
||||
// the original handle number after loading anyways. Seems
|
||||
// like a memory leak in the original implementation.
|
||||
}
|
||||
|
||||
if (*iarray) {
|
||||
delete_page_vars(*iarray);
|
||||
free_page(*iarray);
|
||||
}
|
||||
*iarray = iarray_to_page(&w);
|
||||
iarray_free_writer(&w);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CharSpriteManager_Load(struct page **data)
|
||||
{
|
||||
struct charsprite_manager csm = {0};
|
||||
|
||||
if (!(*data))
|
||||
return false;
|
||||
|
||||
struct iarray_reader r;
|
||||
iarray_init_reader(&r, *data, "CSM");
|
||||
if (iarray_read(&r))
|
||||
return false;
|
||||
|
||||
int nr_handles = iarray_read(&r);
|
||||
if (nr_handles < 0 || nr_handles > 100000)
|
||||
goto error;
|
||||
|
||||
csm.size = nr_handles;
|
||||
csm.sprites = xcalloc(nr_handles, sizeof(struct charsprite*));
|
||||
|
||||
// load handles
|
||||
while (!iarray_end(&r)) {
|
||||
// character data
|
||||
struct charsprite *cs = xcalloc(1, sizeof(struct charsprite));
|
||||
iarray_read(&r); // ???
|
||||
cs->ch = iarray_read_string(&r);
|
||||
cs->tm.face = iarray_read(&r);
|
||||
cs->tm.size = iarray_read(&r);
|
||||
cs->tm.color.r = iarray_read(&r);
|
||||
cs->tm.color.g = iarray_read(&r);
|
||||
cs->tm.color.b = iarray_read(&r);
|
||||
cs->tm.color.a = iarray_read(&r);
|
||||
cs->tm.weight = FW_NORMAL; iarray_read_float(&r); // FIXME
|
||||
cs->tm.outline_left = iarray_read_float(&r);
|
||||
cs->tm.outline_up = cs->tm.outline_left;
|
||||
cs->tm.outline_right = cs->tm.outline_left;
|
||||
cs->tm.outline_down = cs->tm.outline_left;
|
||||
cs->tm.outline_color.r = iarray_read(&r);
|
||||
cs->tm.outline_color.g = iarray_read(&r);
|
||||
cs->tm.outline_color.b = iarray_read(&r);
|
||||
cs->tm.outline_color.a = iarray_read(&r);
|
||||
|
||||
// sprite data
|
||||
int x = iarray_read(&r);
|
||||
int y = iarray_read(&r);
|
||||
sprite_set_show(&cs->sp, false);
|
||||
sprite_set_pos(&cs->sp, x, y);
|
||||
sprite_set_z(&cs->sp, iarray_read(&r));
|
||||
sprite_set_blend_rate(&cs->sp, iarray_read(&r));
|
||||
cs->show = iarray_read(&r);
|
||||
|
||||
// insert charsprite into array
|
||||
int handle = iarray_read(&r) - 2000;
|
||||
if (handle < 0 || (unsigned)handle >= csm.size || csm.sprites[handle]) {
|
||||
sprite_free(&cs->sp);
|
||||
free(cs);
|
||||
goto error;
|
||||
}
|
||||
csm.sprites[handle] = cs;
|
||||
|
||||
if (r.error)
|
||||
goto error;
|
||||
}
|
||||
|
||||
// initialize free list
|
||||
csm.free = xcalloc(csm.size, sizeof(int));
|
||||
for (unsigned i = 0; i < csm.size; i++) {
|
||||
if (!csm.sprites[i])
|
||||
csm.free[csm.nr_free++] = i;
|
||||
}
|
||||
|
||||
if (loaded) {
|
||||
charsprite_manager_free(&load_chars);
|
||||
}
|
||||
load_chars = csm;
|
||||
loaded = true;
|
||||
return true;
|
||||
error:
|
||||
WARNING("CharSpriteManager_Load failed");
|
||||
charsprite_manager_free(&csm);
|
||||
return false;
|
||||
}
|
||||
|
||||
void CharSprite_Release(int handle)
|
||||
{
|
||||
@@ -155,19 +381,6 @@ static void CASCharSpriteProperty_to_text_metrics(struct text_metrics *tm, struc
|
||||
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);
|
||||
@@ -185,19 +398,7 @@ void CharSprite_SetChar(int handle, struct string **s, struct page **property)
|
||||
}
|
||||
|
||||
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);
|
||||
charsprite_render(sp);
|
||||
}
|
||||
|
||||
void CharSprite_SetPos(int handle, int x, int y)
|
||||
|
||||
@@ -895,9 +895,9 @@ HLL_LIBRARY(StoatSpriteEngine,
|
||||
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(CharSpriteManager_Rebuild, CharSpriteManager_Rebuild),
|
||||
HLL_EXPORT(CharSpriteManager_Save, CharSpriteManager_Save),
|
||||
HLL_EXPORT(CharSpriteManager_Load, CharSpriteManager_Load),
|
||||
HLL_EXPORT(CharSprite_Release, CharSprite_Release),
|
||||
HLL_EXPORT(CharSprite_SetChar, CharSprite_SetChar),
|
||||
HLL_EXPORT(CharSprite_SetPos, CharSprite_SetPos),
|
||||
|
||||
@@ -61,6 +61,12 @@ void iarray_write(struct iarray_writer *w, int data)
|
||||
w->data[w->size++] = data;
|
||||
}
|
||||
|
||||
void iarray_write_float(struct iarray_writer *w, float data)
|
||||
{
|
||||
union { float f; int i; } cast = { .f = data };
|
||||
iarray_write(w, cast.i);
|
||||
}
|
||||
|
||||
void iarray_write_string(struct iarray_writer *w, struct string *s)
|
||||
{
|
||||
for (char *p = s->text; *p ;p++) {
|
||||
@@ -166,6 +172,12 @@ int iarray_read(struct iarray_reader *r)
|
||||
return r->data[r->pos++].i;
|
||||
}
|
||||
|
||||
float iarray_read_float(struct iarray_reader *r)
|
||||
{
|
||||
union { float f; int i; } cast = { .i = iarray_read(r) };
|
||||
return cast.f;
|
||||
}
|
||||
|
||||
struct string *iarray_read_string(struct iarray_reader *r)
|
||||
{
|
||||
int c;
|
||||
|
||||
@@ -34,6 +34,7 @@ struct iarray_writer {
|
||||
void iarray_init_writer(struct iarray_writer *w, const char *header);
|
||||
void iarray_free_writer(struct iarray_writer *w);
|
||||
void iarray_write(struct iarray_writer *w, int data);
|
||||
void iarray_write_float(struct iarray_writer *w, float data);
|
||||
void iarray_write_string(struct iarray_writer *w, struct string *s);
|
||||
void iarray_write_struct(struct iarray_writer *w, struct page *page);
|
||||
void iarray_write_array(struct iarray_writer *w, struct page *page);
|
||||
@@ -47,8 +48,14 @@ struct iarray_reader {
|
||||
int error;
|
||||
};
|
||||
|
||||
static inline bool iarray_end(struct iarray_reader *r)
|
||||
{
|
||||
return r->pos >= r->size;
|
||||
}
|
||||
|
||||
bool iarray_init_reader(struct iarray_reader *r, struct page *a, const char *header);
|
||||
int iarray_read(struct iarray_reader *r);
|
||||
float iarray_read_float(struct iarray_reader *r);
|
||||
struct string *iarray_read_string(struct iarray_reader *r);
|
||||
struct page *iarray_read_struct(struct iarray_reader *r, int struct_type);
|
||||
struct page *iarray_read_array(struct iarray_reader *r, struct ain_type *t);
|
||||
|
||||
Reference in New Issue
Block a user