From bb263269295f8d7a562f5b33302de4758789ffb5 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Thu, 15 May 2025 09:13:50 +0900 Subject: [PATCH] draw_plugin: Add free() method It is called when the plugin is unbound from a sprite, or when the sprite to which the plugin is bound is released. This prevents memory leaks when sprites are destroyed without the plugin being released, and simplifies lifetime management of the DrawDungeon plugin. --- include/dungeon/dungeon.h | 3 +-- include/plugin.h | 1 + src/dungeon/dungeon.c | 33 ++++++++++++++++++--------------- src/hll/DrawDungeon.c | 34 ++++++++-------------------------- src/hll/DrawRain.c | 10 +++++++--- src/hll/DrawRipple.c | 13 +++++++++---- src/hll/DrawSnow.c | 13 +++++++++---- src/sprite.c | 6 +++++- 8 files changed, 58 insertions(+), 55 deletions(-) diff --git a/include/dungeon/dungeon.h b/include/dungeon/dungeon.h index f8214fd..070c765 100644 --- a/include/dungeon/dungeon.h +++ b/include/dungeon/dungeon.h @@ -67,8 +67,7 @@ struct dungeon_context { GLuint depth_buffer; }; -struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int surface); -void dungeon_context_free(struct dungeon_context *ctx); +struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int width, int height); 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_set_walked(int surface, int x, int y, int z, int flag); diff --git a/include/plugin.h b/include/plugin.h index 26dcecf..baf6d64 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -24,6 +24,7 @@ struct sact_sprite; struct draw_plugin { const char *name; + void (*free)(struct draw_plugin *); void (*update)(struct sact_sprite *); void (*render)(struct sact_sprite *); // for custom sprites cJSON *(*to_json)(struct sact_sprite *, bool); diff --git a/src/dungeon/dungeon.c b/src/dungeon/dungeon.c index 7063b45..d7dc2e3 100644 --- a/src/dungeon/dungeon.c +++ b/src/dungeon/dungeon.c @@ -47,39 +47,42 @@ #define M_PI (3.14159265358979323846) #endif +static const char plugin_name[] = "DrawDungeon"; + static void dungeon_render(struct sact_sprite *sp); static cJSON *dungeon_to_json(struct sact_sprite *sp, bool verbose); +static void dungeon_context_free(struct draw_plugin *plugin); -struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int surface) +struct dungeon_context *dungeon_get_context(int surface) +{ + struct sact_sprite *sp = sact_try_get_sprite(surface); + if (!sp || !sp->plugin || sp->plugin->name != plugin_name) + return NULL; + return (struct dungeon_context *)sp->plugin; +} + +struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int width, int height) { struct dungeon_context *ctx = xcalloc(1, sizeof(struct dungeon_context)); - ctx->plugin.name = "DrawDungeon"; + ctx->plugin.name = plugin_name; + ctx->plugin.free = dungeon_context_free; ctx->plugin.update = dungeon_render; ctx->plugin.to_json = dungeon_to_json; ctx->version = version; - ctx->surface = surface; - struct sact_sprite *sp = sact_get_sprite(ctx->surface); - if (!sp) - VM_ERROR("DrawDungeon.Init: invalid surface %d", surface); - sprite_bind_plugin(sp, &ctx->plugin); - - gfx_init_texture_blank(&ctx->texture, sp->rect.w, sp->rect.h); + gfx_init_texture_blank(&ctx->texture, width, height); glGenRenderbuffers(1, &ctx->depth_buffer); glBindRenderbuffer(GL_RENDERBUFFER, ctx->depth_buffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, sp->rect.w, sp->rect.h); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); ctx->map = dungeon_map_create(version); return ctx; } -void dungeon_context_free(struct dungeon_context *ctx) +static void dungeon_context_free(struct draw_plugin *plugin) { - struct sact_sprite *sp = sact_try_get_sprite(ctx->surface); - if (sp) - sprite_bind_plugin(sp, NULL); - + struct dungeon_context *ctx = (struct dungeon_context *)plugin; if (ctx->dgn) dgn_free(ctx->dgn); if (ctx->dtx) diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index e48211f..25164ae 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -25,25 +25,18 @@ #include "dungeon/map.h" #include "dungeon/renderer.h" #include "dungeon/tes.h" +#include "sact.h" #include "hll.h" -static struct dungeon_context *current_context = NULL; - static int dungeon_init(enum draw_dungeon_version version, int surface) { - if (current_context) - VM_ERROR("Dungeon is already associated with surface %d", current_context->surface); - if (surface < 0) + struct sact_sprite *sp = sact_get_sprite(surface); + if (!sp) return 0; - current_context = dungeon_context_create(version, surface); - return 1; -} -struct dungeon_context *dungeon_get_context(int surface) -{ - if (!current_context || surface != current_context->surface) - return NULL; - return current_context; + struct dungeon_context *ctx = dungeon_context_create(version, sp->rect.w, sp->rect.h); + sprite_bind_plugin(sp, &ctx->plugin); + return 1; } static struct dgn_cell *dungeon_get_cell(int surface, int x, int y, int z) @@ -54,14 +47,6 @@ static struct dgn_cell *dungeon_get_cell(int surface, int x, int y, int z) return dgn_cell_at(ctx->dgn, x, y, z); } -static void DrawDungeon_ModuleFini(void) -{ - if (current_context) { - dungeon_context_free(current_context); - current_context = NULL; - } -} - static int DrawDungeon_Init(int surface) { return dungeon_init(DRAW_DUNGEON_1, surface); @@ -74,11 +59,9 @@ static int DrawDungeon14_Init(int surface) static void DrawDungeon_Release(int surface) { - struct dungeon_context *ctx = dungeon_get_context(surface); - if (!ctx) + if (!dungeon_get_context(surface)) return; - dungeon_context_free(ctx); - current_context = NULL; + sprite_bind_plugin(sact_get_sprite(surface), NULL); } static void DrawDungeon_SetDrawFlag(int surface, int flag) @@ -284,7 +267,6 @@ HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, StopTimer, void); HLL_QUIET_UNIMPLEMENTED( , void, DrawDungeon, RestartTimer, void); #define DRAW_DUNGEON_EXPORTS \ - HLL_EXPORT(_ModuleFini, DrawDungeon_ModuleFini), \ HLL_EXPORT(Release, DrawDungeon_Release), \ HLL_EXPORT(SetDrawFlag, DrawDungeon_SetDrawFlag), \ HLL_EXPORT(BeginLoad, DrawDungeon_BeginLoad), \ diff --git a/src/hll/DrawRain.c b/src/hll/DrawRain.c index 1f7c9e8..f50a9f1 100644 --- a/src/hll/DrawRain.c +++ b/src/hll/DrawRain.c @@ -45,6 +45,11 @@ static struct draw_rain_plugin *get_draw_rain_plugin(int surface) return (struct draw_rain_plugin *)sp->plugin; } +static void DrawRain_free(struct draw_plugin *plugin) +{ + free(plugin); +} + static void DrawRain_update(struct sact_sprite *sp) { struct draw_rain_plugin *plugin = (struct draw_rain_plugin *)sp->plugin; @@ -95,6 +100,7 @@ static int DrawRain_Init(int surface) } struct draw_rain_plugin *plugin = xcalloc(1, sizeof(struct draw_rain_plugin)); plugin->p.name = plugin_name; + plugin->p.free = DrawRain_free; plugin->p.update = DrawRain_update; plugin->p.to_json = DrawRain_to_json; plugin->nr_lines = 1000; @@ -107,11 +113,9 @@ static int DrawRain_Init(int surface) static void DrawRain_Release(int surface) { - struct draw_rain_plugin *plugin = get_draw_rain_plugin(surface); - if (!plugin) + if (!get_draw_rain_plugin(surface)) return; sprite_bind_plugin(sact_get_sprite(surface), NULL); - free(plugin); } static void DrawRain_SetNumofLine(int surface, int line) diff --git a/src/hll/DrawRipple.c b/src/hll/DrawRipple.c index 7f54eae..711e8b9 100644 --- a/src/hll/DrawRipple.c +++ b/src/hll/DrawRipple.c @@ -52,6 +52,13 @@ static struct draw_ripple_plugin *get_draw_ripple_plugin(int surface) return (struct draw_ripple_plugin *)sp->plugin; } +static void DrawRipple_free(struct draw_plugin *_plugin) +{ + struct draw_ripple_plugin *plugin = (struct draw_ripple_plugin *)_plugin; + free(plugin->ripples); + free(plugin); +} + static void draw_point(uint32_t *pixels, int w, int h, int x, int y) { if (x < 0 || x >= w || y < 0 || y >= h) @@ -163,6 +170,7 @@ static int DrawRipple_Init(int surface) } struct draw_ripple_plugin *plugin = xcalloc(1, sizeof(struct draw_ripple_plugin)); plugin->p.name = plugin_name; + plugin->p.free = DrawRipple_free; plugin->p.update = DrawRipple_update; plugin->p.to_json = DrawRipple_to_json; plugin->width = 6; @@ -175,12 +183,9 @@ static int DrawRipple_Init(int surface) static void DrawRipple_Release(int surface) { - struct draw_ripple_plugin *plugin = get_draw_ripple_plugin(surface); - if (!plugin) + if (!get_draw_ripple_plugin(surface)) return; sprite_bind_plugin(sact_get_sprite(surface), NULL); - free(plugin->ripples); - free(plugin); } static void DrawRipple_SetNumof(int surface, int numof) diff --git a/src/hll/DrawSnow.c b/src/hll/DrawSnow.c index 7ae3f17..9d2d266 100644 --- a/src/hll/DrawSnow.c +++ b/src/hll/DrawSnow.c @@ -70,6 +70,13 @@ static struct draw_snow_plugin *get_draw_snow_plugin(int sprite) return (struct draw_snow_plugin *)sp->plugin; } +static void DrawSnow_free(struct draw_plugin *_plugin) +{ + struct draw_snow_plugin *plugin = (struct draw_snow_plugin *)_plugin; + free(plugin->particles); + free(plugin); +} + static void DrawSnow_update(struct sact_sprite *sp) { struct draw_snow_plugin *plugin = (struct draw_snow_plugin *)sp->plugin; @@ -131,6 +138,7 @@ static void DrawSnow_Init(int sprite, int width, int height) { struct draw_snow_plugin *plugin = xcalloc(1, sizeof(struct draw_snow_plugin)); plugin->p.name = plugin_name; + plugin->p.free = DrawSnow_free; plugin->p.update = DrawSnow_update; plugin->p.render = DrawSnow_render; plugin->p.to_json = DrawSnow_to_json; @@ -147,12 +155,9 @@ static void DrawSnow_Init(int sprite, int width, int height) static void DrawSnow_Release(int sprite) { - struct draw_snow_plugin *plugin = get_draw_snow_plugin(sprite); - if (!plugin) + if (!get_draw_snow_plugin(sprite)) return; sprite_bind_plugin(sact_get_sprite(sprite), NULL); - free(plugin->particles); - free(plugin); } static void DrawSnow_Start(int sprite) diff --git a/src/sprite.c b/src/sprite.c index 6c98a8e..931d37e 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -54,8 +54,10 @@ 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) + if (sp->plugin && sp->plugin->free) { + sp->plugin->free(sp->plugin); LIST_REMOVE(sp, entry); + } // restore to initial state memset(sp, 0, sizeof(struct sact_sprite)); sprite_init(sp); @@ -470,6 +472,8 @@ void sprite_bind_plugin(struct sact_sprite *sp, struct draw_plugin *plugin) LIST_INSERT_HEAD(&sprites_with_plugins, sp, entry); else if (sp->plugin && !plugin) LIST_REMOVE(sp, entry); + if (sp->plugin != plugin && sp->plugin && sp->plugin->free) + sp->plugin->free(sp->plugin); sp->plugin = plugin; }