Fix reference counting of SACT CGs

This fixes a bug where enemies disappear in Rance 5D battles.
This commit is contained in:
kichikuou
2021-11-07 21:23:45 +09:00
parent 0bbb6fbeae
commit ca1e47c093
6 changed files with 100 additions and 160 deletions
+38 -65
View File
@@ -56,11 +56,8 @@ static cginfo_t *cgs[CGMAX];
CG_xxxで作成したCGを参照する
@param no: 読み込むCG番号
@param refinc: 参照カウンタを増やすかどうか。
spriteから参照されるときは増やし、CG_xxxを作る時に
参照されるときは増やさない。
*/
cginfo_t *nt_scg_loadcg_no(int no, boolean refinc) {
static cginfo_t *nt_scg_get(int no) {
cginfo_t *i;
if (no >= (CGMAX -1)) {
@@ -68,19 +65,13 @@ cginfo_t *nt_scg_loadcg_no(int no, boolean refinc) {
return NULL;
}
// すでに ロードされているか、CG_xxx で作成ずみの場合は
// 参照カウンタを増やす
if (cgs[no] != NULL) {
if (refinc) {
cgs[no]->refcnt++;
}
if (cgs[no] != NULL)
return cgs[no];
}
i = malloc(sizeof(cginfo_t));
i->type = CG_LINKED;
i->no = no;
i->refcnt = (refinc ? 1 : 0);
i->refcnt = 1;
i->sf = sf_loadcg_no(no -1);
if (i->sf == NULL) {
WARNING("load fail (%d)\n", no -1);
@@ -93,6 +84,22 @@ cginfo_t *nt_scg_loadcg_no(int no, boolean refinc) {
return i;
}
cginfo_t *nt_scg_addref(int no) {
cginfo_t *info = nt_scg_get(no);
if (info)
info->refcnt++;
return info;
}
void nt_scg_deref(cginfo_t *cg) {
if (--cg->refcnt > 0)
return;
if (cg->sf)
sf_free(cg->sf);
free(cg);
}
// 指定の大きさ、色の矩形の CG を作成
int nt_scg_create(int wNumCG, int wWidth, int wHeight, int wR, int wG, int wB, int wBlendRate) {
cginfo_t *i;
@@ -124,14 +131,14 @@ int nt_scg_create_reverse(int wNumCG, int wNumSrcCG, int wReverseX, int wReverse
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = nt_scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = nt_scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_REVERSE;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
src = srccg->sf;
i->sf = stretch(src, src->width, src->height, (wReverseX << 1) | wReverseY);
@@ -152,14 +159,14 @@ int nt_scg_create_stretch(int wNumCG, int wWidth, int wHeight, int wNumSrcCG) {
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = nt_scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = nt_scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_STRETCH;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
src = srccg->sf;
i->sf = stretch(src, wWidth, wHeight, 0);
@@ -181,14 +188,14 @@ int nt_scg_create_blend(int wNumDstCG, int wNumBaseCG, int wX, int wY, int wNumB
spcg_assert_no(wNumBlendCG);
// 元にするCGを参照 (LINKCGなら読み込み)
basecg = nt_scg_loadcg_no(wNumBaseCG, FALSE);
blendcg = nt_scg_loadcg_no(wNumBlendCG, FALSE);
if (basecg == NULL || blendcg == NULL) return NG;
basecg = nt_scg_get(wNumBaseCG);
blendcg = nt_scg_get(wNumBlendCG);
if (!basecg || !blendcg) return NG;
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumDstCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = blend(basecg->sf, wX , wY, blendcg->sf, wAlphaMapMode);
@@ -214,7 +221,7 @@ int nt_scg_create_text(int wNumCG, int wSize, int wR, int wG, int wB, char *cTex
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = sf_create_surface(glyph->width, wSize, nact->ags.dib->depth);
gr_fill(i->sf, 0, 0, glyph->width, wSize, wR, wG, wB);
@@ -250,7 +257,7 @@ int nt_scg_create_textnum(int wNumCG, int wSize, int wR, int wG, int wB, int wFi
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = sf_create_surface(glyph->width, wSize, nact->ags.dib->depth);
gr_fill(i->sf, 0, 0, glyph->width, wSize, wR, wG, wB);
gr_draw_amap(i->sf, 0, 0, glyph->pixel, glyph->width, wSize, glyph->bytes_per_line);
@@ -271,14 +278,14 @@ int nt_scg_copy(int wNumDstCG, int wNumSrcCG) {
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = nt_scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = nt_scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumDstCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = sf_dup(srccg->sf);
// もし前に作成したものがあり、未開放の場合は開放
@@ -298,14 +305,14 @@ int nt_scg_cut(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth, int wHe
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = nt_scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = nt_scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumDstCG;
i->refcnt = 0;
i->refcnt = 1;
src = srccg->sf;
if (src->alpha) {
@@ -339,14 +346,14 @@ int nt_scg_partcopy(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth, in
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = nt_scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = nt_scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumDstCG;
i->refcnt = 0;
i->refcnt = 1;
src = srccg->sf;
if (src->alpha) {
@@ -388,51 +395,17 @@ int nt_scg_freeall() {
* されていない(参照数が0の)場合のみ、オブジェクトを削除
*/
int nt_scg_free(int no) {
cginfo_t *cg;
spcg_assert_no(no);
if (NULL == (cg = cgs[no])) return NG;
cginfo_t *cg = cgs[no];
if (!cg) return NG;
// 参照数が0の時のみオブジェクトを開放
if (cg->refcnt == 0) {
nt_scg_free_cgobj(cg);
}
// 番号で消したときはオブジェクトが開放されなくても
// オブジェクトリストから削除
nt_scg_deref(cg);
cgs[no] = NULL;
return OK;
}
/**
* CG オブジェクトの開放
*/
int nt_scg_free_cgobj(cginfo_t *cg) {
if (cg == NULL) return NG;
(cg->refcnt)--;
// 他でまだ参照していれば開放しない
if (cg->refcnt > 0) {
return NG;
}
// CG本体の開放
if (cg->sf) {
sf_free(cg->sf);
}
// 削除するオブジェクトを参照しているオブジェクトリストも削除
if (cg == cgs[cg->no]) {
cgs[cg->no] = NULL;
}
free(cg);
return OK;
}
// CGの種類を取得
int nt_scg_querytype(int wNumCG, int *ret) {
if (wNumCG >= (CGMAX -1)) goto errexit;
+2 -2
View File
@@ -27,7 +27,8 @@
#include "portab.h"
#include "night.h"
extern cginfo_t *nt_scg_loadcg_no(int no, boolean refinc);
extern cginfo_t *nt_scg_addref(int no);
extern void nt_scg_deref(cginfo_t *cg);
extern int nt_scg_create(int wNumCG, int wWidth, int wHeight, int wR, int wG, int wB, int wBlendRate);
extern int nt_scg_create_reverse(int NumCG, int wNumSrcCG, int wReverseX, int wReverseY);
extern int nt_scg_create_stretch(int wNumCG, int wWidth, int wHeight, int wNumSrcCG);
@@ -39,7 +40,6 @@ extern int nt_scg_cut(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth,
extern int nt_scg_partcopy(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth, int wHeight);
extern int nt_scg_freeall();
extern int nt_scg_free(int cg);
extern int nt_scg_free_cgobj(cginfo_t *cg);
extern int nt_scg_querytype(int wNumCG, int *ret);
extern int nt_scg_querysize(int wNumCG, int *w, int *h);
extern int nt_scg_querybpp(int wNumCG, int *ret);
+10 -15
View File
@@ -17,9 +17,9 @@ sprite_t *nt_sp_new(int no, int cg1, int cg2, int cg3, int type) {
sp->no = no;
sp->type = type;
if (cg1) sp->cg1 = nt_scg_loadcg_no(cg1, TRUE); else sp->cg1 = NULL;
if (cg2) sp->cg2 = nt_scg_loadcg_no(cg2, TRUE); else sp->cg2 = NULL;
if (cg3) sp->cg3 = nt_scg_loadcg_no(cg3, TRUE); else sp->cg3 = NULL;
sp->cg1 = cg1 ? nt_scg_addref(cg1) : NULL;
sp->cg2 = cg2 ? nt_scg_addref(cg2) : NULL;
sp->cg3 = cg3 ? nt_scg_addref(cg3) : NULL;
sp->curcg = sp->cg1;
sp->show = TRUE;
@@ -72,9 +72,9 @@ sprite_t *nt_sp_msg_new(int no, int x, int y, int width, int height) {
void nt_sp_free(sprite_t *sp) {
if (sp == NULL) return;
if (sp->cg1) nt_scg_free_cgobj(sp->cg1);
if (sp->cg2) nt_scg_free_cgobj(sp->cg2);
if (sp->cg3) nt_scg_free_cgobj(sp->cg3);
if (sp->cg1) nt_scg_deref(sp->cg1);
if (sp->cg2) nt_scg_deref(sp->cg2);
if (sp->cg3) nt_scg_deref(sp->cg3);
if (sp->type == SPRITE_MSG) {
sf_free(sp->u.msg.canvas);
@@ -102,15 +102,10 @@ void nt_sp_set_cg(sprite_t *sp, int no) {
if (sp == NULL) return;
if (sp->curcg) {
nt_scg_free_cgobj(sp->curcg);
}
if (no) {
cg = nt_scg_loadcg_no(no, TRUE);
} else {
cg = NULL;
}
if (sp->curcg)
nt_scg_deref(sp->curcg);
cg = no ? nt_scg_addref(no) : NULL;
if (cg == NULL) {
sp->cursize.width = 0;
+38 -66
View File
@@ -53,11 +53,8 @@
CG_xxxで作成したCGを参照する
@param no: 読み込むCG番号
@param refinc: 参照カウンタを増やすかどうか。
spriteから参照されるときは増やし、CG_xxxを作る時に
参照されるときは増やさない。
*/
cginfo_t *scg_loadcg_no(int no, boolean refinc) {
static cginfo_t *scg_get(int no) {
cginfo_t *i;
if (no >= (CGMAX -1)) {
@@ -65,19 +62,13 @@ cginfo_t *scg_loadcg_no(int no, boolean refinc) {
return NULL;
}
// すでに ロードされているか、CG_xxx で作成ずみの場合は
// 参照カウンタを増やす
if (sact.cg[no] != NULL) {
if (refinc) {
sact.cg[no]->refcnt++;
}
if (sact.cg[no] != NULL)
return sact.cg[no];
}
i = malloc(sizeof(cginfo_t));
i->type = CG_LINKED;
i->no = no;
i->refcnt = (refinc ? 1 : 0);
i->refcnt = 1;
i->sf = sf_loadcg_no(no -1);
if (i->sf == NULL) {
WARNING("load fail (%d)\n", no -1);
@@ -90,6 +81,21 @@ cginfo_t *scg_loadcg_no(int no, boolean refinc) {
return i;
}
cginfo_t *scg_addref(int no) {
cginfo_t *info = scg_get(no);
if (info)
info->refcnt++;
return info;
}
void scg_deref(cginfo_t *cg) {
if (--cg->refcnt > 0)
return;
if (cg->sf)
sf_free(cg->sf);
free(cg);
}
// 指定の大きさ、色の矩形の CG を作成
int scg_create(int wNumCG, int wWidth, int wHeight, int wR, int wG, int wB, int wBlendRate) {
@@ -100,7 +106,7 @@ int scg_create(int wNumCG, int wWidth, int wHeight, int wR, int wG, int wB, int
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = sf_create_surface(wWidth, wHeight, sf0->depth);
gr_fill(i->sf, 0, 0, wWidth, wHeight, wR, wG, wB);
gr_fill_alpha_map(i->sf, 0, 0, wWidth, wHeight, wBlendRate);
@@ -122,14 +128,14 @@ int scg_create_reverse(int wNumCG, int wNumSrcCG, int wReverseX, int wReverseY)
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_REVERSE;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
src = srccg->sf;
i->sf = stretch(src, src->width, src->height, (wReverseX << 1) | wReverseY);
@@ -150,14 +156,14 @@ int scg_create_stretch(int wNumCG, int wWidth, int wHeight, int wNumSrcCG) {
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_STRETCH;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
src = srccg->sf;
i->sf = stretch(src, wWidth, wHeight, 0);
@@ -179,14 +185,14 @@ int scg_create_blend(int wNumDstCG, int wNumBaseCG, int wX, int wY, int wNumBlen
spcg_assert_no(wNumBlendCG);
// 元にするCGを参照 (LINKCGなら読み込み)
basecg = scg_loadcg_no(wNumBaseCG, FALSE);
blendcg = scg_loadcg_no(wNumBlendCG, FALSE);
if (basecg == NULL || blendcg == NULL) return NG;
basecg = scg_get(wNumBaseCG);
blendcg = scg_get(wNumBlendCG);
if (!basecg || !blendcg) return NG;
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumDstCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = blend(basecg->sf, wX , wY, blendcg->sf, wAlphaMapMode);
@@ -212,7 +218,7 @@ int scg_create_text(int wNumCG, int wSize, int wR, int wG, int wB, int wText) {
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = sf_create_surface(glyph->width, wSize, nact->ags.dib->depth);
gr_fill(i->sf, 0, 0, glyph->width, wSize, wR, wG, wB);
@@ -248,7 +254,7 @@ int scg_create_textnum(int wNumCG, int wSize, int wR, int wG, int wB, int wFigs,
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = sf_create_surface(glyph->width, wSize, nact->ags.dib->depth);
gr_fill(i->sf, 0, 0, glyph->width, wSize, wR, wG, wB);
gr_draw_amap(i->sf, 0, 0, glyph->pixel, glyph->width, wSize, glyph->bytes_per_line);
@@ -269,14 +275,14 @@ int scg_copy(int wNumDstCG, int wNumSrcCG) {
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumDstCG;
i->refcnt = 0;
i->refcnt = 1;
i->sf = sf_dup(srccg->sf);
// もし前に作成したものがあり、未開放の場合は開放
@@ -296,14 +302,14 @@ int scg_cut(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth, int wHeigh
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumDstCG;
i->refcnt = 0;
i->refcnt = 1;
src = srccg->sf;
if (src->alpha) {
@@ -337,14 +343,14 @@ int scg_partcopy(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth, int w
spcg_assert_no(wNumSrcCG);
// 元にするCGを参照 (LINKCGなら読み込み)
if (NULL == (srccg = scg_loadcg_no(wNumSrcCG, FALSE))) {
if (!(srccg = scg_get(wNumSrcCG))) {
return NG;
}
i = malloc(sizeof(cginfo_t));
i->type = CG_SET;
i->no = wNumDstCG;
i->refcnt = 0;
i->refcnt = 1;
src = srccg->sf;
if (src->alpha) {
@@ -386,51 +392,17 @@ int scg_freeall() {
* されていない(参照数が0の)場合のみ、オブジェクトを削除
*/
int scg_free(int no) {
cginfo_t *cg;
spcg_assert_no(no);
if (NULL == (cg = sact.cg[no])) return NG;
cginfo_t *cg = sact.cg[no];
if (!cg) return NG;
// 参照数が0の時のみオブジェクトを開放
if (cg->refcnt == 0) {
scg_free_cgobj(cg);
}
// 番号で消したときはオブジェクトが開放されなくても
// オブジェクトリストから削除
scg_deref(cg);
sact.cg[no] = NULL;
return OK;
}
/**
* CG オブジェクトの開放
*/
int scg_free_cgobj(cginfo_t *cg) {
if (cg == NULL) return NG;
(cg->refcnt)--;
// 他でまだ参照していれば開放しない
if (cg->refcnt > 0) {
return NG;
}
// CG本体の開放
if (cg->sf) {
sf_free(cg->sf);
}
// 削除するオブジェクトを参照しているオブジェクトリストも削除
if (cg == sact.cg[cg->no]) {
sact.cg[cg->no] = NULL;
}
free(cg);
return OK;
}
// CGの種類を取得
int scg_querytype(int wNumCG, int *ret) {
if (wNumCG >= (CGMAX -1)) goto errexit;
+2 -2
View File
@@ -27,7 +27,8 @@
#include "portab.h"
#include "sact.h"
extern cginfo_t *scg_loadcg_no(int no, boolean refinc);
extern cginfo_t *scg_addref(int no);
extern void scg_deref(cginfo_t *cg);
extern int scg_create(int wNumCG, int wWidth, int wHeight, int wR, int wG, int wB, int wBlendRate);
extern int scg_create_reverse(int NumCG, int wNumSrcCG, int wReverseX, int wReverseY);
extern int scg_create_stretch(int wNumCG, int wWidth, int wHeight, int wNumSrcCG);
@@ -39,7 +40,6 @@ extern int scg_cut(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth, int
extern int scg_partcopy(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth, int wHeight);
extern int scg_freeall();
extern int scg_free(int cg);
extern int scg_free_cgobj(cginfo_t *cg);
extern int scg_querytype(int wNumCG, int *ret);
extern int scg_querysize(int wNumCG, int *w, int *h);
extern int scg_querybpp(int wNumCG, int *ret);
+10 -10
View File
@@ -147,9 +147,9 @@ int sp_new(int no, int cg1, int cg2, int cg3, int type) {
sp->no = no;
// set時点でのcgが使用される(draw時ではない)
if (cg1) sp->cg1 = scg_loadcg_no(cg1, TRUE); else sp->cg1 = NULL;
if (cg2) sp->cg2 = scg_loadcg_no(cg2, TRUE); else sp->cg2 = NULL;
if (cg3) sp->cg3 = scg_loadcg_no(cg3, TRUE); else sp->cg3 = NULL;
sp->cg1 = cg1 ? scg_addref(cg1) : NULL;
sp->cg2 = cg2 ? scg_addref(cg2) : NULL;
sp->cg3 = cg3 ? scg_addref(cg3) : NULL;
//初期のcurcgはcg1
sp->curcg = sp->cg1;
@@ -238,11 +238,10 @@ int sp_new_msg(int no, int x, int y, int width, int height) {
int sp_set_wall_paper(int no) {
sprite_t *sp = sact.sp[0];
if (sp->curcg) {
scg_free_cgobj(sp->curcg);
}
if (sp->curcg)
scg_deref(sp->curcg);
sp->curcg = no ? scg_loadcg_no(no, TRUE) : NULL;
sp->curcg = no ? scg_addref(no) : NULL;
if (sp->curcg) { // display specified CG
sp->update = DEFAULT_UPDATE;
@@ -287,9 +286,10 @@ int sp_free(int no) {
}
// CGオブジェクトの削除
if (sp->cg1) scg_free_cgobj(sp->cg1);
if (sp->cg2) scg_free_cgobj(sp->cg2);
if (sp->cg3) scg_free_cgobj(sp->cg3);
if (sp->cg1) scg_deref(sp->cg1);
if (sp->cg2) scg_deref(sp->cg2);
if (sp->cg3) scg_deref(sp->cg3);
sp->cg1 = sp->cg2 = sp->cg3 = NULL;
// remove時の処理があれば実行
if (sp->remove) {