From 4f75f2d7ed3bae8daa4e11c32c5941aa5e0c3469 Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Sat, 1 May 2021 13:55:08 -0700 Subject: [PATCH] Refactor sact_graphics.c Split the code from sact_graphics.c into sprite.c and hll/SACT2.c. sprite.c contains an index-independent sprite/scene interface, whereas hll/SACT2.c handles the indexing of sprites. This is to better support the StoatSpriteEngine.MultiSprite_* functions, which use a different indexing system. --- include/sact.h | 49 +-- include/sprite.h | 109 +++++++ src/effect.c | 2 +- src/hll/DrawGraph.c | 18 +- src/hll/SACT2.c | 629 ++++++++++++++++++++++++++++++++++---- src/meson.build | 2 +- src/sact_graphics.c | 713 -------------------------------------------- src/sprite.c | 338 +++++++++++++++++++++ subprojects/libsys4 | 2 +- 9 files changed, 1048 insertions(+), 814 deletions(-) create mode 100644 include/sprite.h delete mode 100644 src/sact_graphics.c create mode 100644 src/sprite.c diff --git a/include/sact.h b/include/sact.h index cb40c9a..0e3a577 100644 --- a/include/sact.h +++ b/include/sact.h @@ -18,54 +18,13 @@ #define SYSTEM4_SACT_H #include -#include -#include -#include "queue.h" -#include "gfx/gfx.h" -#include "gfx/types.h" - -struct string; -struct page; -union vm_value; - -struct sact_sprite { - TAILQ_ENTRY(sact_sprite) entry; - struct texture texture; - SDL_Color color; - Rectangle rect; - struct { - struct string *str; - struct texture texture; - Point home; - Point pos; - int char_space; - int line_space; - } text; - int z; - bool show; - int no; - int cg_no; -}; - -extern bool sact_dirty; - -static inline void sprite_dirty(struct sact_sprite *sp) -{ - if (sp && sp->show) - sact_dirty = true; -} +#include "sprite.h" struct sact_sprite *sact_get_sprite(int sp); -struct sact_sprite *sact_get_sprite_dirty(int sp); -struct texture *sact_get_texture(int sp_no); -struct texture *sact_get_texture_dirty(int sp_no); - -void sact_render_scene(void); - void sact_ModuleFini(void); int sact_Init(void *_, int cg_cache_size); -int sact_SetWP(int cg_no); -int sact_SetWP_Color(int r, int g, int b); +#define sact_SetWP sprite_set_wp +#define sact_SetWP_Color sprite_set_wp_color int sact_GetScreenWidth(void); int sact_GetScreenHeight(void); int sact_GetMainSurfaceNumber(void); @@ -74,7 +33,7 @@ int sact_Effect(int type, int time, int key); int sact_SP_GetUnuseNum(int min); int sact_SP_Count(void); int sact_SP_Enum(struct page **array); -int sact_SP_GetMaxZ(void); +#define sact_SP_GetMaxZ sprite_get_max_z int sact_SP_SetCG(int sp, int cg); int sact_SP_Create(int sp, int width, int height, int r, int g, int b, int a); int sact_SP_CreatePixelOnly(int sp, int width, int height); diff --git a/include/sprite.h b/include/sprite.h new file mode 100644 index 0000000..ea9a3f8 --- /dev/null +++ b/include/sprite.h @@ -0,0 +1,109 @@ +/* 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_SPRITE_H +#define SYSTEM4_SPRITE_H + +#include +#include +#include "queue.h" +#include "gfx/gfx.h" + +struct string; +struct page; +union vm_value; + +struct sact_sprite { + TAILQ_ENTRY(sact_sprite) entry; + struct texture texture; + SDL_Color color; + Rectangle rect; + struct { + struct string *str; + struct texture texture; + Point home; + Point pos; + int char_space; + int line_space; + } text; + int z; + bool show; + int no; + int cg_no; +}; + +extern bool sact_dirty; + +static inline void sprite_dirty(struct sact_sprite *sp) +{ + if (sp && sp->show) + sact_dirty = true; +} + +static inline void scene_dirty(void) +{ + sact_dirty = true; +} + + +void sprite_register(struct sact_sprite *sp); +void sprite_unregister(struct sact_sprite *sp); +void sprite_free(struct sact_sprite *sp); +void sprite_render_scene(void); +void sprite_flip(void); +struct texture *sprite_get_texture(struct sact_sprite *sp); +int sprite_set_wp(int cg_no); +int sprite_set_wp_color(int r, int g, int b); +int sprite_set_cg(struct sact_sprite *sp, int cg_no); +void sprite_init(struct sact_sprite *sp, int w, int h, int r, int g, int b, int a); +int sprite_get_max_z(void); +void sprite_set_pos(struct sact_sprite *sp, int x, int y); +void sprite_set_x(struct sact_sprite *sp, int x); +void sprite_set_y(struct sact_sprite *sp, int y); +void sprite_set_z(struct sact_sprite *sp, int z); +int sprite_get_blend_rate(struct sact_sprite *sp); +void sprite_set_blend_rate(struct sact_sprite *sp, int rate); +void sprite_set_show(struct sact_sprite *sp, bool show); +int sprite_set_draw_method(struct sact_sprite *sp, int method); +int sprite_get_draw_method(struct sact_sprite *sp); +int sprite_exists_alpha(struct sact_sprite *sp); +static inline int sprite_get_pos_x(struct sact_sprite *sp) { return sp->rect.x; } +static inline int sprite_get_pos_y(struct sact_sprite *sp) { return sp->rect.y; } +static inline int sprite_get_width(struct sact_sprite *sp) { return sp->rect.w; } +static inline int sprite_get_height(struct sact_sprite *sp) { return sp->rect.h; } +static inline int sprite_get_z(struct sact_sprite *sp) { return sp->z; } +static inline int sprite_get_show(struct sact_sprite *sp) { return sp->show; } +void sprite_set_text_home(struct sact_sprite *sp, int x, int y); +void sprite_set_text_line_space(struct sact_sprite *sp, int px); +void sprite_set_text_char_space(struct sact_sprite *sp, int px); +void sprite_set_text_pos(struct sact_sprite *sp, int x, int y); +void sprite_text_draw(struct sact_sprite *sp, struct string *text, struct text_metrics *tm); +void sprite_text_clear(struct sact_sprite *sp); +void sprite_text_home(struct sact_sprite *sp, int size); +void sprite_text_new_line(struct sact_sprite *sp, int size); +void sprite_text_copy(struct sact_sprite *dsp, struct sact_sprite *ssp); +static inline int sprite_get_text_home_x(struct sact_sprite *sp) { return sp->text.home.x; } +static inline int sprite_get_text_home_y(struct sact_sprite *sp) { return sp->text.home.y; } +static inline int sprite_get_text_char_space(struct sact_sprite *sp) { return sp->text.char_space; } +static inline int sprite_get_text_pos_x(struct sact_sprite *sp) { return sp->text.pos.x; } +static inline int sprite_get_text_pos_y(struct sact_sprite *sp) { return sp->text.pos.y; } +static inline int sprite_get_text_line_space(struct sact_sprite *sp) { return sp->text.line_space; } +bool sprite_is_point_in(struct sact_sprite *sp, int x, int y); +bool sprite_is_point_in_rect(struct sact_sprite *sp, int x, int y); +int sprite_get_amap_value(struct sact_sprite *sp, int x, int y); +void sprite_get_pixel_value(struct sact_sprite *sp, int x, int y, int *r, int *g, int *b); + +#endif /* SYSTEM4_SPRITE_H */ diff --git a/src/effect.c b/src/effect.c index f5bf982..691fa88 100644 --- a/src/effect.c +++ b/src/effect.c @@ -105,7 +105,7 @@ int sact_Effect(int type, possibly_unused int time, possibly_unused int key) // get old & new scene textures Texture old, new; gfx_copy_main_surface(&old); - sact_render_scene(); + sprite_render_scene(); gfx_copy_main_surface(&new); effect_callback effect = effects[type]; diff --git a/src/hll/DrawGraph.c b/src/hll/DrawGraph.c index 776ebba..9fea2e6 100644 --- a/src/hll/DrawGraph.c +++ b/src/hll/DrawGraph.c @@ -19,8 +19,22 @@ #include "gfx/types.h" #include "system4/string.h" -#define STEX(sp_no) sact_get_texture(sp_no) -#define DTEX(sp_no) sact_get_texture_dirty(sp_no) +// Get texture for source sprite +static struct texture *STEX(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return NULL; + return sprite_get_texture(sp); +} + +// Get texture for destination sprite +static struct texture *DTEX(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return NULL; + sprite_dirty(sp); + return sprite_get_texture(sp); +} static void DrawGraph_Copy(int dst, int dx, int dy, int src, int sx, int sy, int w, int h) { diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index e533b8c..28c4b92 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -29,13 +29,537 @@ #include "queue.h" #include "gfx/gfx.h" #include "sact.h" +#include "vm/page.h" #include "xsystem4.h" +static struct sact_sprite *sact_create_sprite(int sp_no, int width, int height, int r, int g, int b, int a); + +static struct sact_sprite **sprites = NULL; +static int nr_sprites = 0; + +// NOTE: Used externally by DrawGraph and SengokuRanceFont +struct sact_sprite *sact_get_sprite(int sp) +{ + if (sp < -1 || sp >= nr_sprites) + return NULL; + return sprites[sp]; +} + +static struct sact_sprite *sact_alloc_sprite(int sp) +{ + sprites[sp] = xcalloc(1, sizeof(struct sact_sprite)); + sprites[sp]->no = sp; + sprite_dirty(sprites[sp]); + return sprites[sp]; +} + +static void sact_free_sprite(struct sact_sprite *sp) +{ + if (sprites[sp->no] == NULL) + VM_ERROR("Double free of sact_sprite"); + sprites[sp->no] = NULL; + sprite_free(sp); +} + +static void realloc_sprite_table(int n) +{ + int old_nr_sprites = nr_sprites; + nr_sprites = n; + + struct sact_sprite **tmp = xrealloc(sprites-1, sizeof(struct sact_sprite*) * (nr_sprites+1)); + sprites = tmp + 1; + + memset(sprites + old_nr_sprites, 0, sizeof(struct sact_sprite*) * (nr_sprites - old_nr_sprites)); +} + +int sact_Init(possibly_unused void *_, possibly_unused int cg_cache_size) +{ + // already initialized + if (sprites) + return 1; + + gfx_init(); + gfx_font_init(); + audio_init(); + + nr_sprites = 256; + sprites = xmalloc(sizeof(struct sact_sprite*) * 257); + memset(sprites, 0, sizeof(struct sact_sprite*) * 257); + + // create sprite for main_surface + Texture *t = gfx_main_surface(); + struct sact_sprite *sp = sact_create_sprite(0, t->w, t->h, 0, 0, 0, 255); + sp->texture = *t; // XXX: textures normally shouldn't be copied like this... + + sprites++; + return 1; +} + +void sact_ModuleFini(void) +{ + for (int i = 0; i < nr_sprites; i++) { + if (sprites[i]) { + sact_free_sprite(sprites[i]); + } + } +} + +//int SACT2_Error(struct string *err); +//int SACT2_WP_GetSP(int sp); +//int SACT2_WP_SetSP(int sp); + +int sact_GetScreenWidth(void) +{ + return config.view_width; +} + +int sact_GetScreenHeight(void) +{ + return config.view_height; +} + +int sact_GetMainSurfaceNumber(void) +{ + return -1; +} + +int sact_Update(void) +{ + handle_events(); + if (sact_dirty) { + sprite_render_scene(); + sprite_flip(); + } + return 1; +} + +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, EffectSetMask, int cg); +//int SACT2_EffectSetMaskSP(int sp); +HLL_WARN_UNIMPLEMENTED( , void, SACT2, QuakeScreen, int amp_x, int amp_y, int time, int key); +//void SACT2_QUAKE_SET_CROSS(int amp_x, int amp_y); +//void SACT2_QUAKE_SET_ROTATION(int amp, int cycle); + +int sact_SP_GetUnuseNum(int min) +{ + for (int i = min; i < nr_sprites; i++) { + if (!sprites[i]) + return i; + } + + int n = max(min, nr_sprites); + realloc_sprite_table(n + 256); + return n; +} + +int sact_SP_Count(void) +{ + int count = 0; + for (int i = 0; i < nr_sprites; i++) { + if (sprites[i]) + count++; + } + return count; +} + +int sact_SP_Enum(struct page **array) +{ + int count = 0; + int size = (*array)->nr_vars; + for (int i = 0; i < nr_sprites && count < size; i++) { + if (sprites[i]) { + (*array)->values[count++].i = i; + } + } + return count; +} + +int sact_SP_SetCG(int sp_no, int cg_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) + sact_SP_Create(sp_no, 1, 1, 0, 0, 0, 255); + if (!(sp = sact_get_sprite(sp_no))) { + WARNING("Failed to create sprite"); + return 0; + } + return sprite_set_cg(sp, cg_no); +} + +//int SACT2_SP_SetCGFromFile(int sp, struct string *filename); +//int SACT2_SP_SaveCG(int sp, struct string *filename); + +static struct sact_sprite *sact_create_sprite(int sp_no, int width, int height, int r, int g, int b, int a) +{ + struct sact_sprite *sp; + if (sp_no < 0) + VM_ERROR("Invalid sprite number: %d", sp_no); + if (sp_no >= nr_sprites) { + realloc_sprite_table(sp_no+256); + } + if (!(sp = sact_get_sprite(sp_no))) + sp = sact_alloc_sprite(sp_no); + + sprite_init(sp, width, height, r, g, b, a); + return sp; +} + +int sact_SP_Create(int sp_no, int width, int height, int r, int g, int b, int a) +{ + sact_create_sprite(sp_no, width, height, r, g, b, a); + return 1; +} + +int sact_SP_CreatePixelOnly(int sp_no, int width, int height) +{ + sact_create_sprite(sp_no, width, height, 0, 0, 0, -1); + return 1; +} + +//int SACT2_SP_CreateCustom(int sp); + +int sact_SP_Delete(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sact_free_sprite(sp); + return 1; +} + +int sact_SP_SetPos(int sp_no, int x, int y) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 1; + sprite_set_pos(sp, x, y); + return 1; +} + +int sact_SP_SetX(int sp_no, int x) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_set_x(sp, x); + return 1; +} + +int sact_SP_SetY(int sp_no, int y) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_set_y(sp, y); + return 1; +} + +int sact_SP_SetZ(int sp_no, int z) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_set_z(sp, z); + return 1; +} + +int sact_SP_GetBlendRate(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_blend_rate(sp); +} + +int sact_SP_SetBlendRate(int sp_no, int rate) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_set_blend_rate(sp, rate); + return 1; +} + +int sact_SP_SetShow(int sp_no, bool show) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_set_show(sp, show); + return 1; +} + +int sact_SP_SetDrawMethod(int sp_no, int method) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_set_draw_method(sp, method); + return 1; +} + +int sact_SP_GetDrawMethod(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return DRAW_METHOD_NORMAL; + return sprite_get_draw_method(sp); +} + +int sact_SP_IsUsing(int sp_no) +{ + return sact_get_sprite(sp_no) != NULL; +} + +int sact_SP_ExistsAlpha(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_exists_alpha(sp); +} + +int sact_SP_GetPosX(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_pos_x(sp); +} + +int sact_SP_GetPosY(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_pos_y(sp); +} + +int sact_SP_GetWidth(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_width(sp); +} + +int sact_SP_GetHeight(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_height(sp); +} + +int sact_SP_GetZ(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_z(sp); +} + +int sact_SP_GetShow(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_show(sp); +} + +int sact_SP_SetTextHome(int sp_no, int x, int y) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_set_text_home(sp, x, y); + return 1; +} + +int sact_SP_SetTextLineSpace(int sp_no, int px) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 1; + sprite_set_text_line_space(sp, px); + return 1; +} + +int sact_SP_SetTextCharSpace(int sp_no, int px) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 1; + sprite_set_text_char_space(sp, px); + return 1; +} + +int sact_SP_SetTextPos(int sp_no, int x, int y) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_set_text_pos(sp, x, y); + return 1; +} + +static void init_text_metrics(struct text_metrics *tm, union vm_value *_tm) +{ + *tm = (struct text_metrics) { + .color = { + .r = _tm[0].i, + .g = _tm[1].i, + .b = _tm[2].i, + .a = 255 + }, + .outline_color = { + .r = _tm[10].i, + .g = _tm[11].i, + .b = _tm[12].i, + .a = 255 + }, + .size = _tm[3].i, + .weight = _tm[4].i, + .face = _tm[5].i, + .outline_left = _tm[6].i, + .outline_up = _tm[7].i, + .outline_right = _tm[8].i, + .outline_down = _tm[9].i, + }; +} + +int _sact_SP_TextDraw(int sp_no, struct string *text, struct text_metrics *tm) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_text_draw(sp, text, tm); + return 1; +} + +int sact_SP_TextDraw(int sp_no, struct string *text, struct page *_tm) +{ + struct text_metrics tm; + init_text_metrics(&tm, _tm->values); + _sact_SP_TextDraw(sp_no, text, &tm); + return 1; +} + +int sact_SP_TextClear(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_text_clear(sp); + return 1; +} + +int sact_SP_TextHome(int sp_no, int size) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_text_home(sp, size); + return 1; +} + +int sact_SP_TextNewLine(int sp_no, int size) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_text_new_line(sp, size); + return 1; +} + +//int SACT2_SP_TextBackSpace(int sp_no); + +int sact_SP_TextCopy(int dno, int sno) +{ + struct sact_sprite *dsp = sact_get_sprite(dno); + struct sact_sprite *ssp = sact_get_sprite(sno); + if (!ssp) + return 0; + if (!dsp) { + sact_SP_Create(dno, 1, 1, 0, 0, 0, 0); + if (!(dsp = sact_get_sprite(dno))) { + WARNING("Failed to create sprite"); + return 0; + } + } + + sprite_text_copy(dsp, ssp); + return 1; +} + +int sact_SP_GetTextHomeX(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_text_home_x(sp); +} + +int sact_SP_GetTextHomeY(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_text_home_y(sp); +} + +int sact_SP_GetTextCharSpace(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_text_char_space(sp); +} + +int sact_SP_GetTextPosX(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_text_pos_x(sp); +} + +int sact_SP_GetTextPosY(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_text_pos_y(sp); +} + +int sact_SP_GetTextLineSpace(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_text_line_space(sp); +} + +int sact_SP_IsPtIn(int sp_no, int x, int y) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_is_point_in(sp, x, y); +} + +int sact_SP_IsPtInRect(int sp_no, int x, int y) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_is_point_in_rect(sp, x, y); +} + +int sact_CG_GetMetrics(int cg_no, struct page **page) +{ + union vm_value *cgm = (*page)->values; + struct cg_metrics metrics; + if (!cg_get_metrics(ald[ALDFILE_CG], cg_no - 1, &metrics)) + return 0; + cgm[0].i = metrics.w; + cgm[1].i = metrics.h; + cgm[2].i = metrics.bpp; + cgm[3].i = metrics.has_pixel; + cgm[4].i = metrics.has_alpha; + cgm[5].i = metrics.pixel_pitch; + cgm[6].i = metrics.alpha_pitch; + return 1; +} + +int sact_SP_GetAMapValue(int sp_no, int x, int y) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + return sprite_get_amap_value(sp, x, y); +} + +int sact_SP_GetPixelValue(int sp_no, int x, int y, int *r, int *g, int *b) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) return 0; + sprite_get_pixel_value(sp, x, y, r, g, b); + return 1; +} + static int sact_GAME_MSG_GetNumOf(void) { return ain->nr_messages; } +//void SACT2_GAME_MSG_Get(int index, struct string **text); + static void sact_IntToZenkaku(struct string **s, int value, int figures, int zero_pad) { int i; @@ -56,6 +580,8 @@ static void sact_IntToHankaku(struct string **s, int value, int figures, int zer string_append_cstr(s, buf, i); } +//int SACT2_StringPopFront(struct string **dst, struct string **src); + static int sact_Mouse_GetPos(int *x, int *y) { handle_events(); @@ -90,6 +616,9 @@ static int sact_Joypad_IsKeyDown(int num, int key) return 0; // TODO } +//int SACT2_Joypad_GetNumof(void); +HLL_WARN_UNIMPLEMENTED( , void, SACT2, JoypadQuake_Set, int num, int type, int magnitude); + static bool sact_Joypad_GetAnalogStickStatus(int num, int type, float *degree, float *power) { //hll_unimplemented_warning(SACT2, Joypad_GetAnalogStickStatus); @@ -125,6 +654,17 @@ static int sact_CG_IsExist(int cg_no) return ald[ALDFILE_CG] && archive_exists(ald[ALDFILE_CG], cg_no - 1); } +//int SACT2_CSV_Load(struct string *filename); +//int SACT2_CSV_Save(void); +//int SACT2_CSV_SaveAs(struct string *filename); +//int SACT2_CSV_CountLines(void); +//int SACT2_CSV_CountColumns(void); +//void SACT2_CSV_Get(struct string **s, int line, int column); +//int SACT2_CSV_Set(int line, int column, struct string *data); +//int SACT2_CSV_GetInt(int line, int column); +//void SACT2_CSV_SetInt(int line, int column, int data); +//void SACT2_CSV_Realloc(int lines, int columns); + static int sact_Music_IsExist(int n) { return bgm_exists(n - 1); @@ -155,11 +695,27 @@ static int sact_Music_IsPlay(int ch) return bgm_is_playing(ch); } +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_SetLoopCount, int ch, int count); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetLoopCount, int ch); +//int SACT2_Music_SetLoopStartPos(int ch, int pos); +//int SACT2_Music_SetLoopEndPos(int ch, int pos); + static int sact_Music_Fade(int ch, int time, int volume, int stop) { return bgm_fade(ch, time, volume, stop); } +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_StopFade, int ch); +HLL_WARN_UNIMPLEMENTED(0, int, SACT2, Music_IsFade, int ch); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_Pause, int ch); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_Restart, int ch); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_IsPause, int ch); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetPos, int ch); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetLength, int ch); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetSamplePos, int ch); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetSampleLength, int ch); +HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_Seek, int ch, int pos); + static int sact_Sound_IsExist(int n) { return wav_exists(n - 1); @@ -195,21 +751,34 @@ static int sact_Sound_IsPlay(int ch) return wav_is_playing(ch); } +//int SACT2_Sound_SetLoopCount(int ch, int count); +//int SACT2_Sound_GetLoopCount(int ch); + static int sact_Sound_Fade(int ch, int time, int volume, int stop) { return wav_fade(ch, time, volume, stop); } +//int SACT2_Sound_StopFade(int ch); +//int SACT2_Sound_IsFade(int ch); +//int SACT2_Sound_GetPos(int ch); +//int SACT2_Sound_GetLength(int ch); + static int sact_Sound_ReverseLR(int ch) { return wav_reverse_LR(ch); } +//int SACT2_Sound_GetVolume(int ch); + static int sact_Sound_GetTimeLength(int ch) { return wav_get_time_length(ch); } +//int SACT2_Sound_GetGroupNum(int ch); +//bool SACT2_Sound_PrepareFromFile(int ch, struct string *filename); + static void sact_System_GetDate(int *year, int *month, int *mday, int *wday) { time_t t = time(NULL); @@ -234,61 +803,19 @@ static void sact_System_GetTime(int *hour, int *min, int *sec, int *ms) *ms = ts.tv_nsec / 1000000; } +//void SACT2_CG_RotateRGB(int dst, int dx, int dy, int w, int h, int rotate_type); + static void sact_CG_BlendAMapBin(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int border) { - gfx_copy_use_amap_border(sact_get_texture_dirty(dst), dx, dy, sact_get_texture(src), sx, sy, w, h, border); + struct sact_sprite *dsp = sact_get_sprite(dst); + struct sact_sprite *ssp = sact_get_sprite(src); + if (!dsp) return; + struct texture *dtx = sprite_get_texture(dsp); + struct texture *stx = ssp ? sprite_get_texture(ssp) : NULL; + gfx_copy_use_amap_border(dtx, dx, dy, stx, sx, sy, w, h, border); + sprite_dirty(dsp); } -//int SACT2_Error(struct string *err); -//int SACT2_WP_GetSP(int sp); -//int SACT2_WP_SetSP(int sp); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, EffectSetMask, int cg); -//int SACT2_EffectSetMaskSP(int sp); -HLL_WARN_UNIMPLEMENTED( , void, SACT2, QuakeScreen, int amp_x, int amp_y, int time, int key); -//void SACT2_QUAKE_SET_CROSS(int amp_x, int amp_y); -//void SACT2_QUAKE_SET_ROTATION(int amp, int cycle); -//int SACT2_SP_SetCGFromFile(int sp, struct string *filename); -//int SACT2_SP_SaveCG(int sp, struct string *filename); -//int SACT2_SP_CreateCustom(int sp); -//int SACT2_SP_TextBackSpace(int sp_no); -//void SACT2_GAME_MSG_Get(int index, struct string **text); -//int SACT2_StringPopFront(struct string **dst, struct string **src); -//int SACT2_Joypad_GetNumof(void); -HLL_WARN_UNIMPLEMENTED( , void, SACT2, JoypadQuake_Set, int num, int type, int magnitude); -//int SACT2_CSV_Load(struct string *filename); -//int SACT2_CSV_Save(void); -//int SACT2_CSV_SaveAs(struct string *filename); -//int SACT2_CSV_CountLines(void); -//int SACT2_CSV_CountColumns(void); -//void SACT2_CSV_Get(struct string **s, int line, int column); -//int SACT2_CSV_Set(int line, int column, struct string *data); -//int SACT2_CSV_GetInt(int line, int column); -//void SACT2_CSV_SetInt(int line, int column, int data); -//void SACT2_CSV_Realloc(int lines, int columns); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_SetLoopCount, int ch, int count); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetLoopCount, int ch); -//int SACT2_Music_SetLoopStartPos(int ch, int pos); -//int SACT2_Music_SetLoopEndPos(int ch, int pos); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_StopFade, int ch); -HLL_WARN_UNIMPLEMENTED(0, int, SACT2, Music_IsFade, int ch); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_Pause, int ch); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_Restart, int ch); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_IsPause, int ch); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetPos, int ch); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetLength, int ch); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetSamplePos, int ch); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_GetSampleLength, int ch); -HLL_WARN_UNIMPLEMENTED(1, int, SACT2, Music_Seek, int ch, int pos); -//int SACT2_Sound_SetLoopCount(int ch, int count); -//int SACT2_Sound_GetLoopCount(int ch); -//int SACT2_Sound_StopFade(int ch); -//int SACT2_Sound_IsFade(int ch); -//int SACT2_Sound_GetPos(int ch); -//int SACT2_Sound_GetLength(int ch); -//int SACT2_Sound_GetVolume(int ch); -//int SACT2_Sound_GetGroupNum(int ch); -//bool SACT2_Sound_PrepareFromFile(int ch, struct string *filename); -//void SACT2_CG_RotateRGB(int dst, int dx, int dy, int w, int h, int rotate_type); //void SACT2_Debug_Pause(void); //void SACT2_Debug_GetFuncStack(struct string **s, int nest); HLL_WARN_UNIMPLEMENTED(0, int, SACT2, SP_SetBrightness, int sp_no, int brightness); diff --git a/src/meson.build b/src/meson.build index 858bbd9..15e4692 100644 --- a/src/meson.build +++ b/src/meson.build @@ -10,8 +10,8 @@ xsystem4 = ['audio.c', 'input.c', 'page.c', 'resume.c', - 'sact_graphics.c', 'savedata.c', + 'sprite.c', 'system4.c', 'text.c', 'video.c', diff --git a/src/sact_graphics.c b/src/sact_graphics.c deleted file mode 100644 index b80ac83..0000000 --- a/src/sact_graphics.c +++ /dev/null @@ -1,713 +0,0 @@ -/* 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 "system4.h" -#include "system4/ald.h" -#include "system4/cg.h" -#include "system4/string.h" -#include "system4/utfsjis.h" - -#include "audio.h" -#include "input.h" -#include "gfx/gfx.h" -#include "sact.h" -#include "vm.h" -#include "vm/page.h" -#include "xsystem4.h" - -static struct sact_sprite *create_sprite(int sp_no, int width, int height, int r, int g, int b, int a); - -bool sact_dirty = true; - -static struct sact_sprite **sprites = NULL; -static int nr_sprites = 0; - -// wallpaper -static struct sact_sprite wp; - -TAILQ_HEAD(listhead, sact_sprite) sprite_list = - TAILQ_HEAD_INITIALIZER(sprite_list); - -static void sprite_register(struct sact_sprite *sp) -{ - struct sact_sprite *p; - TAILQ_FOREACH(p, &sprite_list, entry) { - if (p->z > sp->z) { - TAILQ_INSERT_BEFORE(p, sp, entry); - return; - } - } - TAILQ_INSERT_TAIL(&sprite_list, sp, entry); -} - -static void sprite_unregister(struct sact_sprite *sp) -{ - TAILQ_REMOVE(&sprite_list, sp, entry); -} - -struct sact_sprite *sact_get_sprite(int sp) -{ - if (sp < -1 || sp >= nr_sprites) - return NULL; - return sprites[sp]; -} - -struct sact_sprite *sact_get_sprite_dirty(int sp) -{ - if (sp < -1 || sp >= nr_sprites) - return NULL; - sprite_dirty(sprites[sp]); - return sprites[sp]; -} - -struct texture *sact_get_texture(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) - return NULL; - if (!sp->texture.handle) { - gfx_init_texture_with_color(&sp->texture, sp->rect.w, sp->rect.h, sp->color); - } - return &sp->texture; -} - -struct texture *sact_get_texture_dirty(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) - return NULL; - if (!sp->texture.handle) { - gfx_init_texture_with_color(&sp->texture, sp->rect.w, sp->rect.h, sp->color); - } - return &sp->texture; - -} - -static struct sact_sprite *alloc_sprite(int sp) -{ - sprites[sp] = xcalloc(1, sizeof(struct sact_sprite)); - sprites[sp]->no = sp; - sprite_dirty(sprites[sp]); - return sprites[sp]; -} - -static void free_sprite(struct sact_sprite *sp) -{ - if (sprites[sp->no] == NULL) - VM_ERROR("Double free of sact_sprite"); - if (sp->show) - sprite_unregister(sp); - sprites[sp->no] = NULL; - gfx_delete_texture(&sp->texture); - gfx_delete_texture(&sp->text.texture); - free(sp); -} - -static void realloc_sprite_table(int n) -{ - int old_nr_sprites = nr_sprites; - nr_sprites = n; - - struct sact_sprite **tmp = xrealloc(sprites-1, sizeof(struct sact_sprite*) * (nr_sprites+1)); - sprites = tmp + 1; - - memset(sprites + old_nr_sprites, 0, sizeof(struct sact_sprite*) * (nr_sprites - old_nr_sprites)); -} - -int sact_Init(possibly_unused void *_, possibly_unused int cg_cache_size) -{ - // already initialized - if (sprites) - return 1; - - gfx_init(); - gfx_font_init(); - audio_init(); - - nr_sprites = 256; - sprites = xmalloc(sizeof(struct sact_sprite*) * 257); - memset(sprites, 0, sizeof(struct sact_sprite*) * 257); - - // create sprite for main_surface - Texture *t = gfx_main_surface(); - struct sact_sprite *sp = create_sprite(0, t->w, t->h, 0, 0, 0, 255); - sp->texture = *t; // XXX: textures normally shouldn't be copied like this... - - sprites++; - return 1; -} - -void sact_ModuleFini(void) -{ - for (int i = 0; i < nr_sprites; i++) { - if (sprites[i]) { - free_sprite(sprites[i]); - } - } -} - -int sact_SetWP(int cg_no) -{ - if (!cg_no) { - gfx_delete_texture(&wp.texture); - return 1; - } - - struct cg *cg = cg_load(ald[ALDFILE_CG], cg_no - 1); - if (!cg) - return 0; - - gfx_delete_texture(&wp.texture); - gfx_init_texture_with_cg(&wp.texture, cg); - cg_free(cg); - sact_dirty = true; - return 1; -} - -int sact_SetWP_Color(int r, int g, int b) -{ - gfx_set_clear_color(r, g, b, 255); - return 1; -} - -int sact_GetScreenWidth(void) -{ - return config.view_width; -} - -int sact_GetScreenHeight(void) -{ - return config.view_height; -} - -int sact_GetMainSurfaceNumber(void) -{ - return -1; -} - -void sact_render_scene(void) -{ - gfx_clear(); - if (wp.texture.handle) { - Rectangle r = RECT(0, 0, wp.texture.w, wp.texture.h); - gfx_render_texture(&wp.texture, &r); - } - struct sact_sprite *p; - TAILQ_FOREACH(p, &sprite_list, entry) { - if (!p->texture.handle) { - gfx_init_texture_with_color(&p->texture, p->rect.w, p->rect.h, p->color); - } - gfx_render_texture(&p->texture, &p->rect); - if (p->text.texture.handle) { - gfx_render_texture(&p->text.texture, &p->rect); - } - } -} - -int sact_Update(void) -{ - handle_events(); - if (sact_dirty) { - sact_render_scene(); - gfx_swap(); - sact_dirty = false; - } - return 1; -} - -int sact_SP_GetUnuseNum(int min) -{ - for (int i = min; i < nr_sprites; i++) { - if (!sprites[i]) - return i; - } - - int n = max(min, nr_sprites); - realloc_sprite_table(n + 256); - return n; -} - -int sact_SP_Count(void) -{ - int count = 0; - for (int i = 0; i < nr_sprites; i++) { - if (sprites[i]) - count++; - } - return count; -} - -int sact_SP_Enum(struct page **array) -{ - int count = 0; - int size = (*array)->nr_vars; - for (int i = 0; i < nr_sprites && count < size; i++) { - if (sprites[i]) { - (*array)->values[count++].i = i; - } - } - return count; -} - -int sact_SP_GetMaxZ(void) -{ - if (TAILQ_EMPTY(&sprite_list)) - return 0; - return TAILQ_LAST(&sprite_list, listhead)->z; -} - -int sact_SP_SetCG(int sp_no, int cg_no) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) - sact_SP_Create(sp_no, 1, 1, 0, 0, 0, 255); - if (!(sp = sact_get_sprite(sp_no))) { - WARNING("Failed to create sprite"); - return 0; - } - struct cg *cg = cg_load(ald[ALDFILE_CG], cg_no - 1); - if (!cg) - return 0; - gfx_init_texture_with_cg(&sp->texture, cg); - sp->rect.w = cg->metrics.w; - sp->rect.h = cg->metrics.h; - sp->cg_no = cg_no; - cg_free(cg); - return 1; -} - -static struct sact_sprite *create_sprite(int sp_no, int width, int height, int r, int g, int b, int a) -{ - struct sact_sprite *sp; - if (sp_no < 0) - VM_ERROR("Invalid sprite number: %d", sp_no); - if (sp_no >= nr_sprites) { - realloc_sprite_table(sp_no+256); - } - if (!(sp = sact_get_sprite_dirty(sp_no))) - sp = alloc_sprite(sp_no); - sp->color = (SDL_Color) { .r = r, .g = g, .b = b, .a = (a >= 0 ? a : 255) }; - sp->rect.w = width; - sp->rect.h = height; - if (!sp->show) { - sp->show = true; - sprite_register(sp); - } - gfx_delete_texture(&sp->texture); - return sp; -} - -int sact_SP_Create(int sp_no, int width, int height, int r, int g, int b, int a) -{ - create_sprite(sp_no, width, height, r, g, b, a); - return 1; -} - -int sact_SP_CreatePixelOnly(int sp_no, int width, int height) -{ - create_sprite(sp_no, width, height, 0, 0, 0, -1); - return 1; -} - -int sact_SP_Delete(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - free_sprite(sp); - sact_dirty = true; - return 1; -} - -int sact_SP_SetPos(int sp_no, int x, int y) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 1; - sp->rect.x = x; - sp->rect.y = y; - return 1; -} - -int sact_SP_SetX(int sp_no, int x) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - sp->rect.x = x; - return 1; -} - -int sact_SP_SetY(int sp_no, int y) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - sp->rect.y = y; - return 1; -} - -int sact_SP_SetZ(int sp_no, int z) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - sp->z = z; - if (sp->show) { - sprite_unregister(sp); - sprite_register(sp); - } - return 1; - -} - -int sact_SP_GetBlendRate(int sp_no) -{ - struct texture *t = sact_get_texture(sp_no); - return t ? t->alpha_mod : 0; -} - -int sact_SP_SetBlendRate(int sp_no, int rate) -{ - struct texture *t = sact_get_texture_dirty(sp_no); - if (!t) return 0; - t->alpha_mod = max(0, min(255, rate)); - return 1; -} - -int sact_SP_SetShow(int sp_no, bool show) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - if (show == sp->show) - return 1; - sp->show = show; - sprite_dirty(sp); - if (show) - sprite_register(sp); - else - sprite_unregister(sp); - return 1; -} - -int sact_SP_SetDrawMethod(int sp_no, int method) -{ - struct texture *t = sact_get_texture_dirty(sp_no); - if (!t) return 0; - if (method < 0 || method >= NR_DRAW_METHODS) { - WARNING("unknown draw method: %d", method); - return 0; - } - t->draw_method = method; - return 1; -} - -int sact_SP_GetDrawMethod(int sp_no) -{ - struct texture *t = sact_get_texture(sp_no); - if (!t) return DRAW_METHOD_NORMAL; - return t->draw_method; -} - -int sact_SP_IsUsing(int sp_no) -{ - return sact_get_sprite(sp_no) != NULL; -} - -int sact_SP_ExistsAlpha(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->texture.has_alpha; -} - -int sact_SP_GetPosX(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->rect.x; -} - -int sact_SP_GetPosY(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->rect.y; -} - -int sact_SP_GetWidth(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->rect.w; -} - -int sact_SP_GetHeight(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->rect.h; -} - -int sact_SP_GetZ(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->z; -} - -int sact_SP_GetShow(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->show; -} - -int sact_SP_SetTextHome(int sp_no, int x, int y) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - sp->text.home = (Point) { .x = x, .y = y }; - return 1; -} - -int sact_SP_SetTextLineSpace(int sp_no, int px) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 1; - sp->text.line_space = px; - return 1; -} - -int sact_SP_SetTextCharSpace(int sp_no, int px) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 1; - sp->text.char_space = px; - return 1; -} - -int sact_SP_SetTextPos(int sp_no, int x, int y) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - sp->text.pos = (Point) { .x = x, .y = y }; - return 1; -} - -static void init_text_metrics(struct text_metrics *tm, union vm_value *_tm) -{ - *tm = (struct text_metrics) { - .color = { - .r = _tm[0].i, - .g = _tm[1].i, - .b = _tm[2].i, - .a = 255 - }, - .outline_color = { - .r = _tm[10].i, - .g = _tm[11].i, - .b = _tm[12].i, - .a = 255 - }, - .size = _tm[3].i, - .weight = _tm[4].i, - .face = _tm[5].i, - .outline_left = _tm[6].i, - .outline_up = _tm[7].i, - .outline_right = _tm[8].i, - .outline_down = _tm[9].i, - }; -} - -int _sact_SP_TextDraw(int sp_no, struct string *text, struct text_metrics *tm) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - - if (!sp->text.texture.handle) { - SDL_Color c; - if (tm->outline_left || tm->outline_right || tm->outline_up || tm->outline_down) - c = tm->outline_color; - else - c = tm->color; - c.a = 0; - gfx_init_texture_with_color(&sp->text.texture, sp->rect.w, sp->rect.h, c); - } - - sp->text.pos.x += gfx_render_text(&sp->text.texture, sp->text.pos, text->text, tm, sp->text.char_space); - return 1; - -} - -int sact_SP_TextDraw(int sp_no, struct string *text, struct page *_tm) -{ - struct text_metrics tm; - init_text_metrics(&tm, _tm->values); - _sact_SP_TextDraw(sp_no, text, &tm); - return 1; -} - -static void clear_text(struct sact_sprite *sp) -{ - gfx_delete_texture(&sp->text.texture); -} - -int sact_SP_TextClear(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - clear_text(sp); - return 1; -} - -int sact_SP_TextHome(int sp_no, possibly_unused int size) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - // FIXME: do something with nTextSize - sp->text.pos = sp->text.home; - return 1; -} - -int sact_SP_TextNewLine(int sp_no, int size) -{ - struct sact_sprite *sp = sact_get_sprite_dirty(sp_no); - if (!sp) return 0; - sp->text.pos = POINT(sp->text.home.x, sp->text.pos.y + size + sp->text.line_space); - return 1; -} - -int sact_SP_TextCopy(int dno, int sno) -{ - struct sact_sprite *dsp = sact_get_sprite_dirty(dno); - struct sact_sprite *ssp = sact_get_sprite(sno); - if (!ssp) - return 0; - if (!dsp) { - sact_SP_Create(dno, 1, 1, 0, 0, 0, 0); - if (!(dsp = sact_get_sprite(dno))) { - WARNING("Failed to create sprite"); - return 0; - } - } - - clear_text(dsp); - if (ssp->text.texture.handle) { - SDL_Color c = { 0, 0, 0, 0 }; - gfx_init_texture_with_color(&dsp->text.texture, dsp->rect.w, dsp->rect.h, c); - gfx_copy(&dsp->text.texture, 0, 0, &ssp->text.texture, 0, 0, ssp->text.texture.w, ssp->text.texture.h); - gfx_copy_amap(&dsp->text.texture, 0, 0, &ssp->text.texture, 0, 0, ssp->text.texture.w, ssp->text.texture.h); - } - dsp->text.home = ssp->text.home; - dsp->text.pos = ssp->text.pos; - dsp->text.char_space = ssp->text.char_space; - dsp->text.line_space = ssp->text.line_space; - return 1; -} - -int sact_SP_GetTextHomeX(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->text.home.x; -} - -int sact_SP_GetTextHomeY(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->text.home.y; -} - -int sact_SP_GetTextCharSpace(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->text.char_space; -} - -int sact_SP_GetTextPosX(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->text.pos.x; -} - -int sact_SP_GetTextPosY(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->text.pos.y; -} - -int sact_SP_GetTextLineSpace(int sp_no) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - if (!sp) return 0; - return sp->text.line_space; -} - -int sact_SP_IsPtIn(int sp_no, int x, int y) -{ - Point p = POINT(x, y); - struct sact_sprite *sp = sact_get_sprite(sp_no); - - if (!sp || !SDL_PointInRect(&p, &sp->rect)) - return 0; - - Texture *t = sact_get_texture(sp_no); - SDL_Color c = gfx_get_pixel(t, x - sp->rect.x, y - sp->rect.y); - return !!c.a; -} - -int sact_SP_IsPtInRect(int sp_no, int x, int y) -{ - struct sact_sprite *sp = sact_get_sprite(sp_no); - Point p = { .x = x, .y = y }; - if (!sp) return 0; - return !!SDL_PointInRect(&p, &sp->rect); -} - -int sact_CG_GetMetrics(int cg_no, struct page **page) -{ - union vm_value *cgm = (*page)->values; - struct cg_metrics metrics; - if (!cg_get_metrics(ald[ALDFILE_CG], cg_no - 1, &metrics)) - return 0; - cgm[0].i = metrics.w; - cgm[1].i = metrics.h; - cgm[2].i = metrics.bpp; - cgm[3].i = metrics.has_pixel; - cgm[4].i = metrics.has_alpha; - cgm[5].i = metrics.pixel_pitch; - cgm[6].i = metrics.alpha_pitch; - return 1; -} - -int sact_SP_GetAMapValue(int sp_no, int x, int y) -{ - Texture *t = sact_get_texture(sp_no); - SDL_Color c = gfx_get_pixel(t, x, y); - return c.a; -} - -int sact_SP_GetPixelValue(int sp_no, int x, int y, int *r, int *g, int *b) -{ - Texture *t = sact_get_texture(sp_no); - SDL_Color c = gfx_get_pixel(t, x, y); - *r = c.r; - *g = c.g; - *b = c.b; - return 1; -} diff --git a/src/sprite.c b/src/sprite.c new file mode 100644 index 0000000..083ecaa --- /dev/null +++ b/src/sprite.c @@ -0,0 +1,338 @@ +/* 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 "system4.h" +#include "system4/ald.h" +#include "system4/cg.h" +#include "system4/string.h" +#include "system4/utfsjis.h" + +#include "audio.h" +#include "input.h" +#include "gfx/gfx.h" +#include "sprite.h" +#include "vm.h" +#include "vm/page.h" +#include "xsystem4.h" + +bool sact_dirty = true; + +static struct sact_sprite wp; + +TAILQ_HEAD(listhead, sact_sprite) sprite_list = + TAILQ_HEAD_INITIALIZER(sprite_list); + +void sprite_register(struct sact_sprite *sp) +{ + struct sact_sprite *p; + TAILQ_FOREACH(p, &sprite_list, entry) { + if (p->z > sp->z) { + TAILQ_INSERT_BEFORE(p, sp, entry); + return; + } + } + TAILQ_INSERT_TAIL(&sprite_list, sp, entry); + if (sp->show) + scene_dirty(); +} + +void sprite_unregister(struct sact_sprite *sp) +{ + TAILQ_REMOVE(&sprite_list, sp, entry); + if (sp->show) + scene_dirty(); +} + +void sprite_free(struct sact_sprite *sp) +{ + if (sp->show) + sprite_unregister(sp); + gfx_delete_texture(&sp->texture); + gfx_delete_texture(&sp->text.texture); + free(sp); +} + +void sprite_render_scene(void) +{ + gfx_clear(); + if (wp.texture.handle) { + Rectangle r = RECT(0, 0, wp.texture.w, wp.texture.h); + gfx_render_texture(&wp.texture, &r); + } + struct sact_sprite *p; + TAILQ_FOREACH(p, &sprite_list, entry) { + if (!p->texture.handle) { + gfx_init_texture_with_color(&p->texture, p->rect.w, p->rect.h, p->color); + } + gfx_render_texture(&p->texture, &p->rect); + if (p->text.texture.handle) { + gfx_render_texture(&p->text.texture, &p->rect); + } + } +} + +void sprite_flip(void) +{ + gfx_swap(); + sact_dirty = false; +} + +struct texture *sprite_get_texture(struct sact_sprite *sp) +{ + if (!sp->texture.handle) { + gfx_init_texture_with_color(&sp->texture, sp->rect.w, sp->rect.h, sp->color); + } + return &sp->texture; +} + +int sprite_set_wp(int cg_no) +{ + if (!cg_no) { + gfx_delete_texture(&wp.texture); + return 1; + } + + struct cg *cg = cg_load(ald[ALDFILE_CG], cg_no - 1); + if (!cg) + return 0; + + gfx_delete_texture(&wp.texture); + gfx_init_texture_with_cg(&wp.texture, cg); + cg_free(cg); + scene_dirty(); + return 1; +} + +int sprite_set_wp_color(int r, int g, int b) +{ + gfx_set_clear_color(r, g, b, 255); + scene_dirty(); + return 1; +} + + +int sprite_set_cg(struct sact_sprite *sp, int cg_no) +{ + struct cg *cg = cg_load(ald[ALDFILE_CG], cg_no - 1); + if (!cg) + return 0; + gfx_init_texture_with_cg(&sp->texture, cg); + sp->rect.w = cg->metrics.w; + sp->rect.h = cg->metrics.h; + sp->cg_no = cg_no; + cg_free(cg); + sprite_dirty(sp); + return 1; +} + +void sprite_init(struct sact_sprite *sp, int w, int h, int r, int g, int b, int a) +{ + sp->color = (SDL_Color) { .r = r, .g = g, .b = b, .a = (a >= 0 ? a : 255) }; + sp->rect.w = w; + sp->rect.h = h; + if (!sp->show) { + sp->show = true; + sprite_register(sp); + } + gfx_delete_texture(&sp->texture); + sprite_dirty(sp); +} + +int sprite_get_max_z(void) +{ + if (TAILQ_EMPTY(&sprite_list)) + return 0; + return TAILQ_LAST(&sprite_list, listhead)->z; +} + +void sprite_set_pos(struct sact_sprite *sp, int x, int y) +{ + sp->rect.x = x; + sp->rect.y = y; + sprite_dirty(sp); +} + +void sprite_set_x(struct sact_sprite *sp, int x) +{ + sp->rect.x = x; + sprite_dirty(sp); +} + +void sprite_set_y(struct sact_sprite *sp, int y) +{ + sp->rect.y = y; + sprite_dirty(sp); +} + +void sprite_set_z(struct sact_sprite *sp, int z) +{ + sp->z = z; + if (sp->show) { + sprite_unregister(sp); + sprite_register(sp); + } +} + +int sprite_get_blend_rate(struct sact_sprite *sp) +{ + return sprite_get_texture(sp)->alpha_mod; +} + +void sprite_set_blend_rate(struct sact_sprite *sp, int rate) +{ + sprite_get_texture(sp)->alpha_mod = max(0, min(255, rate)); + sprite_dirty(sp); +} + +void sprite_set_show(struct sact_sprite *sp, bool show) +{ + if (show == sp->show) + return; + sp->show = show; + sprite_dirty(sp); + if (show) + sprite_register(sp); + else + sprite_unregister(sp); +} + +int sprite_set_draw_method(struct sact_sprite *sp, int method) +{ + if (method < 0 || method >= NR_DRAW_METHODS) { + WARNING("unknown draw method: %d", method); + return 0; + } + sprite_get_texture(sp)->draw_method = method; + sprite_dirty(sp); + return 1; +} + +int sprite_get_draw_method(struct sact_sprite *sp) +{ + return sprite_get_texture(sp)->draw_method; +} + +int sprite_exists_alpha(struct sact_sprite *sp) +{ + return sp->texture.has_alpha; +} + +void sprite_set_text_home(struct sact_sprite *sp, int x, int y) +{ + sp->text.home = (Point) { .x = x, .y = y }; + sprite_dirty(sp); +} + +void sprite_set_text_line_space(struct sact_sprite *sp, int px) +{ + sp->text.line_space = px; + sprite_dirty(sp); +} + +void sprite_set_text_char_space(struct sact_sprite *sp, int px) +{ + sp->text.char_space = px; + sprite_dirty(sp); +} + +void sprite_set_text_pos(struct sact_sprite *sp, int x, int y) +{ + sp->text.pos = (Point) { .x = x, .y = y }; + sprite_dirty(sp); +} + +void sprite_text_draw(struct sact_sprite *sp, struct string *text, struct text_metrics *tm) +{ + if (!sp->text.texture.handle) { + SDL_Color c; + if (tm->outline_left || tm->outline_right || tm->outline_up || tm->outline_down) + c = tm->outline_color; + else + c = tm->color; + c.a = 0; + gfx_init_texture_with_color(&sp->text.texture, sp->rect.w, sp->rect.h, c); + } + + sp->text.pos.x += gfx_render_text(&sp->text.texture, sp->text.pos, text->text, tm, sp->text.char_space); + sprite_dirty(sp); +} + +void sprite_text_clear(struct sact_sprite *sp) +{ + gfx_delete_texture(&sp->text.texture); + sprite_dirty(sp); +} + +void sprite_text_home(struct sact_sprite *sp, possibly_unused int size) +{ + // FIXME: do something with nTextSize + sp->text.pos = sp->text.home; + sprite_dirty(sp); +} + +void sprite_text_new_line(struct sact_sprite *sp, int size) +{ + sp->text.pos = POINT(sp->text.home.x, sp->text.pos.y + size + sp->text.line_space); + sprite_dirty(sp); +} + +void sprite_text_copy(struct sact_sprite *dsp, struct sact_sprite *ssp) +{ + sprite_text_clear(dsp); + if (ssp->text.texture.handle) { + SDL_Color c = { 0, 0, 0, 0 }; + gfx_init_texture_with_color(&dsp->text.texture, dsp->rect.w, dsp->rect.h, c); + gfx_copy(&dsp->text.texture, 0, 0, &ssp->text.texture, 0, 0, ssp->text.texture.w, ssp->text.texture.h); + gfx_copy_amap(&dsp->text.texture, 0, 0, &ssp->text.texture, 0, 0, ssp->text.texture.w, ssp->text.texture.h); + } + dsp->text.home = ssp->text.home; + dsp->text.pos = ssp->text.pos; + dsp->text.char_space = ssp->text.char_space; + dsp->text.line_space = ssp->text.line_space; + sprite_dirty(dsp); +} + +bool sprite_is_point_in_rect(struct sact_sprite *sp, int x, int y) +{ + Point p = POINT(x, y); + return !!SDL_PointInRect(&p, &sp->rect); +} + +bool sprite_is_point_in(struct sact_sprite *sp, int x, int y) +{ + if (!sprite_is_point_in_rect(sp, x, y)) + return 0; + + // check alpha + struct texture *t = sprite_get_texture(sp); + SDL_Color c = gfx_get_pixel(t, x - sp->rect.x, y - sp->rect.y); + return !!c.a; +} + +int sprite_get_amap_value(struct sact_sprite *sp, int x, int y) +{ + return gfx_get_pixel(sprite_get_texture(sp), x, y).a; +} + +void sprite_get_pixel_value(struct sact_sprite *sp, int x, int y, int *r, int *g, int *b) +{ + SDL_Color c = gfx_get_pixel(sprite_get_texture(sp), x, y); + *r = c.r; + *g = c.g; + *b = c.b; +} diff --git a/subprojects/libsys4 b/subprojects/libsys4 index 9c1b705..db29ca8 160000 --- a/subprojects/libsys4 +++ b/subprojects/libsys4 @@ -1 +1 @@ -Subproject commit 9c1b705830c50e1605250a2898096b02f52eb172 +Subproject commit db29ca871423828a668fee735c5ba7780758163e