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.
This commit is contained in:
kichikuou
2025-05-16 09:13:10 +09:00
parent f50c9f6d77
commit bb26326929
8 changed files with 58 additions and 55 deletions
+1 -2
View File
@@ -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);
+1
View File
@@ -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);
+18 -15
View File
@@ -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)
+8 -26
View File
@@ -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), \
+7 -3
View File
@@ -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)
+9 -4
View File
@@ -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)
+9 -4
View File
@@ -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)
+5 -1
View File
@@ -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;
}