From fd4cd139f897ca5986d25dd8c22386360d17d9c0 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Mon, 30 May 2022 09:54:56 +0900 Subject: [PATCH 1/2] Introduce draw_plugin This introduces draw_plugin struct that can be attached to a sprite. The update() function of attached plugin is called every frame by sact_Update(). This corresponds to the DrawPlugin mechanism of System4/SACT2. This is currently used only from DrawDungeon. The 3D engine for Toushin Toshi 3 etc. will also use this. --- include/dungeon/dungeon.h | 4 ++-- include/plugin.h | 25 +++++++++++++++++++++++++ include/scene.h | 3 +++ include/sprite.h | 1 + src/dungeon/dungeon.c | 14 +++++++++++++- src/hll/DrawDungeon.c | 6 ------ src/hll/SACT2.c | 2 +- src/scene.c | 10 ++++++++++ src/sprite.c | 7 +++++++ 9 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 include/plugin.h diff --git a/include/dungeon/dungeon.h b/include/dungeon/dungeon.h index affde29..c3d4389 100644 --- a/include/dungeon/dungeon.h +++ b/include/dungeon/dungeon.h @@ -21,6 +21,7 @@ #include #include #include "gfx/gl.h" +#include "plugin.h" struct page; struct dgn; @@ -51,6 +52,7 @@ struct camera { */ struct dungeon_context { + struct draw_plugin plugin; enum draw_dungeon_version version; int surface; bool loaded; @@ -68,7 +70,6 @@ struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version void dungeon_context_free(struct dungeon_context *ctx); bool dungeon_load(struct dungeon_context *ctx, int num); void dungeon_set_camera(int surface, float x, float y, float z, float angle, float angle_p); -void dungeon_render(struct dungeon_context *ctx); void dungeon_set_walked(int surface, int x, int y, int z, int flag); int dungeon_get_walked(int surface, int x, int y, int z); int dungeon_calc_conquer(int surface); @@ -76,6 +77,5 @@ bool dungeon_load_walk_data(int surface, int map, struct page **page); bool dungeon_save_walk_data(int surface, int map, struct page **page); struct dungeon_context *dungeon_get_context(int surface); -void dungeon_update(void); #endif /* SYSTEM4_DUNGEON_H */ diff --git a/include/plugin.h b/include/plugin.h new file mode 100644 index 0000000..ecb99a5 --- /dev/null +++ b/include/plugin.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2022 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_PLUGIN_H +#define SYSTEM4_PLUGIN_H + +struct draw_plugin { + const char *name; + void (*update)(struct draw_plugin *); +}; + +#endif /* SYSTEM4_PLUGIN_H */ diff --git a/include/scene.h b/include/scene.h index 1b12365..fbd511f 100644 --- a/include/scene.h +++ b/include/scene.h @@ -39,12 +39,15 @@ struct sprite { bool in_scene; // The rendering function. void (*render)(struct sprite*); + // (optional) Draw plugin bound to this sprite. + struct draw_plugin *plugin; }; extern bool scene_is_dirty; void scene_register_sprite(struct sprite *sp); void scene_unregister_sprite(struct sprite *sp); +void scene_update(void); void scene_render(void); int scene_set_wp(int cg_no); int scene_set_wp_color(int r, int g, int b); diff --git a/include/sprite.h b/include/sprite.h index da18bd8..9938390 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -104,6 +104,7 @@ 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); +void sprite_bind_plugin(struct sact_sprite *sp, struct draw_plugin *plugin); void print_sprite(struct sact_sprite *sp); diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index 2e3a484..b9b3b16 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -45,9 +45,13 @@ #define M_PI (3.14159265358979323846) #endif +static void dungeon_render(struct draw_plugin *plugin); + struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int surface) { struct dungeon_context *ctx = xcalloc(1, sizeof(struct dungeon_context)); + ctx->plugin.name = "DrawDungeon"; + ctx->plugin.update = dungeon_render; ctx->version = version; ctx->surface = surface; struct sact_sprite *sp = sact_get_sprite(ctx->surface); @@ -56,6 +60,7 @@ struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version // Dungeon scene will be rendered to this texture. struct texture *texture = sprite_get_texture(sp); + sprite_bind_plugin(sp, &ctx->plugin); glGenRenderbuffers(1, &ctx->depth_buffer); glBindRenderbuffer(GL_RENDERBUFFER, ctx->depth_buffer); @@ -68,6 +73,10 @@ struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version void dungeon_context_free(struct dungeon_context *ctx) { + struct sact_sprite *sp = sact_try_get_sprite(ctx->surface); + if (sp) + sprite_bind_plugin(sp, NULL); + if (ctx->dgn) dgn_free(ctx->dgn); if (ctx->dtx) @@ -248,8 +257,11 @@ static void model_view_matrix(struct camera *camera, mat4 out) glm_lookat(eye, camera->pos, up, out); } -void dungeon_render(struct dungeon_context *ctx) +static void dungeon_render(struct draw_plugin *plugin) { + struct dungeon_context *ctx = (struct dungeon_context *)plugin; + if (!ctx->loaded || !ctx->draw_enabled) + return; struct sact_sprite *sp = sact_get_sprite(ctx->surface); sprite_dirty(sp); struct texture *texture = sprite_get_texture(sp); diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index 62695b9..6ecdd6e 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -46,12 +46,6 @@ struct dungeon_context *dungeon_get_context(int surface) return current_context; } -void dungeon_update(void) -{ - if (current_context && current_context->loaded && current_context->draw_enabled) - dungeon_render(current_context); -} - static struct dgn_cell *dungeon_get_cell(int surface, int x, int y, int z) { struct dungeon_context *ctx = dungeon_get_context(surface); diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index ee209bc..ae70058 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -151,7 +151,7 @@ int sact_GetMainSurfaceNumber(void) int sact_Update(void) { handle_events(); - dungeon_update(); + scene_update(); if (scene_is_dirty) { scene_render(); gfx_swap(); diff --git a/src/scene.c b/src/scene.c index 94e6548..e5710da 100644 --- a/src/scene.c +++ b/src/scene.c @@ -22,6 +22,7 @@ #include "asset_manager.h" #include "gfx/gfx.h" +#include "plugin.h" #include "queue.h" #include "scene.h" @@ -64,6 +65,15 @@ void scene_unregister_sprite(struct sprite *sp) scene_dirty(); } +void scene_update(void) +{ + struct sprite *sp; + TAILQ_FOREACH(sp, &sprite_list, entry) { + if (sp->plugin) + sp->plugin->update(sp->plugin); + } +} + void scene_render(void) { gfx_clear(); diff --git a/src/sprite.c b/src/sprite.c index 8e6acf5..da2a8cb 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -29,6 +29,7 @@ #include "input.h" #include "gfx/gfx.h" #include "gfx/font.h" +#include "plugin.h" #include "sprite.h" #include "vm.h" #include "vm/page.h" @@ -322,6 +323,11 @@ void sprite_get_pixel_value(struct sact_sprite *sp, int x, int y, int *r, int *g *b = c.b; } +void sprite_bind_plugin(struct sact_sprite *sp, struct draw_plugin *plugin) +{ + sp->sp.plugin = plugin; +} + static void print_color(SDL_Color *c) { printf("(%d,%d,%d,%d)", c->r, c->g, c->b, c->a); @@ -369,6 +375,7 @@ void print_sprite(struct sact_sprite *sp) printf("\t\thas_alpha = %s,\n", sp->sp.has_alpha ? "true" : "false"); printf("\t\thidden = %s,\n", sp->sp.hidden ? "true" : "false"); printf("\t\tin_scene = %s,\n", sp->sp.in_scene ? "true" : "false"); + printf("\t\tplugin = %s,\n", sp->sp.plugin ? sp->sp.plugin->name : "NULL"); printf("\t},\n"); printf("\ttexture = "); print_texture(&sp->texture, 1); printf(",\n"); printf("\tcolor = "); print_color(&sp->color); printf(",\n"); From 81ff379eb88d387a3f21d8ba9662f9b445e66ed4 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Tue, 31 May 2022 18:13:08 +0900 Subject: [PATCH 2/2] Avoid iterating over the scene for plugins update Now plugin is a member of sact_sprite, and sprite.c manages a list of sprites with plugins. --- include/scene.h | 3 --- include/sprite.h | 5 ++++- src/hll/SACT2.c | 2 +- src/scene.c | 10 ---------- src/sprite.c | 22 ++++++++++++++++++---- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/include/scene.h b/include/scene.h index fbd511f..1b12365 100644 --- a/include/scene.h +++ b/include/scene.h @@ -39,15 +39,12 @@ struct sprite { bool in_scene; // The rendering function. void (*render)(struct sprite*); - // (optional) Draw plugin bound to this sprite. - struct draw_plugin *plugin; }; extern bool scene_is_dirty; void scene_register_sprite(struct sprite *sp); void scene_unregister_sprite(struct sprite *sp); -void scene_update(void); void scene_render(void); int scene_set_wp(int cg_no); int scene_set_wp_color(int r, int g, int b); diff --git a/include/sprite.h b/include/sprite.h index 9938390..a3efe3d 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -30,7 +30,7 @@ struct text_style; struct sact_sprite { struct sprite sp; - TAILQ_ENTRY(sact_sprite) entry; + LIST_ENTRY(sact_sprite) entry; // The sprite's texture (CG or solid color). Initialized lazily. struct texture texture; // If no CG is attached to the sprite, the solid color to fill with. @@ -51,6 +51,8 @@ struct sact_sprite { int no; // The CG number attached to the sprite. int cg_no; + // (optional) Draw plugin bound to this sprite. + struct draw_plugin *plugin; }; static inline void sprite_dirty(struct sact_sprite *sp) @@ -105,6 +107,7 @@ 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); void sprite_bind_plugin(struct sact_sprite *sp, struct draw_plugin *plugin); +void sprite_call_plugins(void); void print_sprite(struct sact_sprite *sp); diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index ae70058..5f13b1d 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -151,7 +151,7 @@ int sact_GetMainSurfaceNumber(void) int sact_Update(void) { handle_events(); - scene_update(); + sprite_call_plugins(); if (scene_is_dirty) { scene_render(); gfx_swap(); diff --git a/src/scene.c b/src/scene.c index e5710da..94e6548 100644 --- a/src/scene.c +++ b/src/scene.c @@ -22,7 +22,6 @@ #include "asset_manager.h" #include "gfx/gfx.h" -#include "plugin.h" #include "queue.h" #include "scene.h" @@ -65,15 +64,6 @@ void scene_unregister_sprite(struct sprite *sp) scene_dirty(); } -void scene_update(void) -{ - struct sprite *sp; - TAILQ_FOREACH(sp, &sprite_list, entry) { - if (sp->plugin) - sp->plugin->update(sp->plugin); - } -} - void scene_render(void) { gfx_clear(); diff --git a/src/sprite.c b/src/sprite.c index da2a8cb..3a914c2 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -37,14 +37,16 @@ bool sact_dirty = true; -TAILQ_HEAD(listhead, sact_sprite) sprite_list = - TAILQ_HEAD_INITIALIZER(sprite_list); +LIST_HEAD(listhead, sact_sprite) sprites_with_plugins = + LIST_HEAD_INITIALIZER(sprites_with_plugins); void sprite_free(struct sact_sprite *sp) { scene_unregister_sprite(&sp->sp); gfx_delete_texture(&sp->texture); gfx_delete_texture(&sp->text.texture); + if (sp->plugin) + LIST_REMOVE(sp, entry); memset(sp, 0, sizeof(struct sact_sprite)); } @@ -325,7 +327,19 @@ void sprite_get_pixel_value(struct sact_sprite *sp, int x, int y, int *r, int *g void sprite_bind_plugin(struct sact_sprite *sp, struct draw_plugin *plugin) { - sp->sp.plugin = plugin; + if (!sp->plugin && plugin) + LIST_INSERT_HEAD(&sprites_with_plugins, sp, entry); + else if (sp->plugin && !plugin) + LIST_REMOVE(sp, entry); + sp->plugin = plugin; +} + +void sprite_call_plugins(void) +{ + struct sact_sprite *sp; + LIST_FOREACH(sp, &sprites_with_plugins, entry) { + sp->plugin->update(sp->plugin); + } } static void print_color(SDL_Color *c) @@ -375,7 +389,6 @@ void print_sprite(struct sact_sprite *sp) printf("\t\thas_alpha = %s,\n", sp->sp.has_alpha ? "true" : "false"); printf("\t\thidden = %s,\n", sp->sp.hidden ? "true" : "false"); printf("\t\tin_scene = %s,\n", sp->sp.in_scene ? "true" : "false"); - printf("\t\tplugin = %s,\n", sp->sp.plugin ? sp->sp.plugin->name : "NULL"); printf("\t},\n"); printf("\ttexture = "); print_texture(&sp->texture, 1); printf(",\n"); printf("\tcolor = "); print_color(&sp->color); printf(",\n"); @@ -387,6 +400,7 @@ void print_sprite(struct sact_sprite *sp) printf("\t\tpos = "); print_point(&sp->text.pos); printf(",\n"); printf("\t\tchar_space = %d,\n", sp->text.char_space); printf("\t\tline_space = %d,\n", sp->text.line_space); + printf("\t\tplugin = %s,\n", sp->plugin ? sp->plugin->name : "NULL"); printf("\t},\n"); printf("\tcg_no = %d\n", sp->cg_no); printf("}\n");