Skip to content
Browse files

[0.1.2-10] Garbage collection \:D/ for pmf/img/wav

  • Loading branch information...
1 parent f0c2bda commit 341c2f0549a49960ca559909c5119c0a2d67a500 @iamgreaser committed
Showing with 194 additions and 50 deletions.
  1. +8 −1 include/common.h
  2. +5 −3 pkg/base/version.lua
  3. +28 −0 src/img.c
  4. +16 −8 src/lua_fetch.h
  5. +43 −22 src/lua_image.h
  6. +39 −13 src/lua_model.h
  7. +9 −3 src/lua_wav.h
  8. +23 −0 src/model.c
  9. +23 −0 src/wav.c
View
9 include/common.h
@@ -19,7 +19,7 @@
#define VERSION_X 1
#define VERSION_Y 2
#define VERSION_A 0
-#define VERSION_Z 9
+#define VERSION_Z 10
// Remember to bump "Z" basically every time you change the engine!
// Remember to bump the version in Lua too!
// Remember to document API changes in a new version!
@@ -38,6 +38,9 @@
// MUST BE A POWER OF TWO
#define WAV_CHN_COUNT 128
+// WARNING: This will eventually be disabled in 0.1.3.
+#define ALLOW_EXPLICIT_FREE
+
//define RENDER_FACE_COUNT 2
#ifndef _MSC_VER
@@ -450,6 +453,7 @@ float equal_power_right(float pan);
// img.c
void img_free(img_t *img);
+void img_gc_set(lua_State *L);
img_t *img_parse_tga(int len, const char *data);
img_t *img_load_tga(const char *fname);
@@ -518,6 +522,7 @@ void model_bone_free(model_bone_t *bone);
model_t *model_new(int bonemax);
model_t *model_extend(model_t *pmf, int bonemax);
void model_free(model_t *pmf);
+void model_gc_set(lua_State *L);
model_t *model_parse_pmf(int len, const char *data);
model_t *model_load_pmf(const char *fname);
int model_save_pmf(model_t *pmf, const char *fname);
@@ -594,6 +599,7 @@ extern float icesackit_vol;
wav_t *wav_parse(char *buf, int len);
wav_t *wav_load(const char *fname);
void wav_kill(wav_t *wav);
+void wav_gc_set(lua_State *L);
#ifndef DEDI
extern int wav_mfreq;
extern int wav_bufsize;
@@ -605,3 +611,4 @@ void wav_chn_kill(wavchn_t *chn);
int wav_init(void);
void wav_deinit(void);
#endif
+
View
8 pkg/base/version.lua
@@ -20,9 +20,9 @@
-- Thanks. --GM
VERSION_ENGINE = {
- cmp={0,1,2,0,9},
- num=4259840+9,
- str="0.1.2-9",
+ cmp={0,1,2,0,10},
+ num=4259840+10,
+ str="0.1.2-10",
}
-- 0.1: 4194304
@@ -126,5 +126,7 @@ VERSION_BUGS = {
{intro=nil, fix=4259840+6, msg="JSON writing not supported"},
{intro=nil, fix=4259840+7, msg="General JSON support is broken"},
{intro=nil, fix=4259840+9, msg="UDP sending can crash if DNS lookup fails"},
+{intro=nil, fix=4259840+10, msg="Garbage collection not supported"},
+{intro=4259840+10, fix=nil, msg="Garbage collection incomplete (only pmf/img/wav supported)"},
}
View
28 src/img.c
@@ -42,9 +42,37 @@ uint32_t img_convert_color_to_32(uint32_t v, int bits)
void img_free(img_t *img)
{
+#ifdef USE_OPENGL
+ if(img->tex != 0)
+ glDeleteTextures(1, &(img->tex));
+#endif
+
free(img);
}
+int img_gc_lua(lua_State *L)
+{
+ img_t **img_ud = (img_t **)lua_touserdata(L, 1);
+ img_t *img = *img_ud;
+ if(img != NULL)
+ {
+#ifdef ALLOW_EXPLICIT_FREE
+ printf("Freeing img @ %p\n", img);
+#endif
+ img_free(img);
+ }
+
+ return 0;
+}
+
+void img_gc_set(lua_State *L)
+{
+ lua_newtable(L);
+ lua_pushcfunction(L, img_gc_lua);
+ lua_setfield(L, -2, "__gc");
+ lua_setmetatable(L, -2);
+}
+
img_t *img_parse_tga(int len, const char *data)
{
// TODO: make this routine safer
View
24 src/lua_fetch.h
@@ -84,28 +84,32 @@ int icelua_fnaux_fetch_immediate(lua_State *L, const char *ftype, const char *fn
if(pmf == NULL)
return 0;
- lua_pushlightuserdata(L, pmf);
+ *(model_t **)lua_newuserdata(L, sizeof(void *)) = pmf;
+ model_gc_set(L);
return 1;
} else if(!strcmp(ftype, "tga")) {
img_t *img = img_load_tga(fname);
if(img == NULL)
return 0;
- lua_pushlightuserdata(L, img);
+ *(img_t **)lua_newuserdata(L, sizeof(void *)) = img;
+ img_gc_set(L);
return 1;
} else if(!strcmp(ftype, "png")) {
img_t *img = img_load_png(fname);
if(img == NULL)
return 0;
- lua_pushlightuserdata(L, img);
+ *(img_t **)lua_newuserdata(L, sizeof(void *)) = img;
+ img_gc_set(L);
return 1;
} else if(!strcmp(ftype, "wav")) {
wav_t *wav = wav_load(fname);
if(wav == NULL)
return 0;
- lua_pushlightuserdata(L, wav);
+ *(wav_t **)lua_newuserdata(L, sizeof(void *)) = wav;
+ wav_gc_set(L);
return 1;
} else if(!strcmp(ftype, "it")) {
it_module_t *mus = sackit_module_load(fname);
@@ -279,7 +283,8 @@ int icelua_fn_common_fetch_poll(lua_State *L)
break;
}
- lua_pushlightuserdata(L, pmf);
+ *(model_t **)lua_newuserdata(L, sizeof(void *)) = pmf;
+ model_gc_set(L);
ret = 1;
} break;
@@ -294,7 +299,8 @@ int icelua_fn_common_fetch_poll(lua_State *L)
break;
}
- lua_pushlightuserdata(L, img);
+ *(img_t **)lua_newuserdata(L, sizeof(void *)) = img;
+ img_gc_set(L);
ret = 1;
} break;
@@ -309,7 +315,8 @@ int icelua_fn_common_fetch_poll(lua_State *L)
break;
}
- lua_pushlightuserdata(L, img);
+ *(img_t **)lua_newuserdata(L, sizeof(void *)) = img;
+ img_gc_set(L);
ret = 1;
} break;
@@ -324,7 +331,8 @@ int icelua_fn_common_fetch_poll(lua_State *L)
break;
}
- lua_pushlightuserdata(L, wav);
+ *(wav_t **)lua_newuserdata(L, sizeof(void *)) = wav;
+ wav_gc_set(L);
ret = 1;
} break;
View
65 src/lua_image.h
@@ -26,9 +26,12 @@ int icelua_fn_client_img_blit(lua_State *L)
float scalex, scaley;
uint32_t color;
- img_t *img = (img_t*)lua_touserdata(L, 1);
- if(img == NULL || img->udtype != UD_IMG)
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
return luaL_error(L, "not an image");
+ img_t **img_ud = (img_t**)lua_touserdata(L, 1);
+ if(img_ud == NULL || (*img_ud)->udtype != UD_IMG)
+ return luaL_error(L, "not an image");
+ img_t *img = *img_ud;
dx = lua_tointeger(L, 2);
dy = lua_tointeger(L, 3);
@@ -57,12 +60,18 @@ int icelua_fn_client_img_blit_to(lua_State *L)
float scalex, scaley;
uint32_t color;
- img_t *dest = (img_t*)lua_touserdata(L, 1);
- if(dest == NULL || dest->udtype != UD_IMG)
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not an image");
+ if(lua_islightuserdata(L, 2) || !lua_isuserdata(L, 2))
+ return luaL_error(L, "not an image");
+ img_t **dest_ud = (img_t**)lua_touserdata(L, 1);
+ if(dest_ud == NULL || (*dest_ud)->udtype != UD_IMG)
return luaL_error(L, "not an image");
- img_t *source = (img_t*)lua_touserdata(L, 2);
- if(source == NULL || source->udtype != UD_IMG)
+ img_t **source_ud = (img_t**)lua_touserdata(L, 2);
+ if(source_ud == NULL || (*source_ud)->udtype != UD_IMG)
return luaL_error(L, "not an image");
+ img_t *dest = *dest_ud;
+ img_t *source = *source_ud;
dx = lua_tointeger(L, 3);
dy = lua_tointeger(L, 4);
@@ -112,9 +121,10 @@ int icelua_fn_common_img_load(lua_State *L)
lua_pushvalue(L, 1);
lua_call(L, 2, 1);
- img_t *img = (img_t*)lua_touserdata(L, -1);
- if(img == NULL)
+ img_t **img_ud = (img_t**)lua_touserdata(L, -1);
+ if(img_ud == NULL)
return 0;
+ img_t *img = *img_ud;
lua_pushinteger(L, img->head.width);
lua_pushinteger(L, img->head.height);
@@ -165,7 +175,8 @@ int icelua_fn_common_img_new(lua_State *L)
img->tex_dirty = 1;
#endif
- lua_pushlightuserdata(L, img);
+ *(img_t **)lua_newuserdata(L, sizeof(void *)) = img;
+ img_gc_set(L);
return 1;
}
@@ -173,9 +184,12 @@ int icelua_fn_common_img_pixel_set(lua_State *L)
{
int top = icelua_assert_stack(L, 4, 4);
- img_t *img = (img_t*)lua_touserdata(L, 1);
- if(img == NULL || img->udtype != UD_IMG)
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not an image");
+ img_t **img_ud = (img_t**)lua_touserdata(L, 1);
+ if(img_ud == NULL || (*img_ud)->udtype != UD_IMG)
return luaL_error(L, "not an image");
+ img_t *img = *img_ud;
int x = lua_tointeger(L, 2);
int y = lua_tointeger(L, 3);
uint32_t color = lua_tointeger(L, 4);
@@ -203,9 +217,12 @@ int icelua_fn_common_img_fill(lua_State *L)
int top = icelua_assert_stack(L, 2, 2);
- img_t *img = (img_t*)lua_touserdata(L, 1);
- if(img == NULL || img->udtype != UD_IMG)
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not an image");
+ img_t **img_ud = (img_t**)lua_touserdata(L, 1);
+ if(img_ud == NULL || (*img_ud)->udtype != UD_IMG)
return luaL_error(L, "not an image");
+ img_t *img = *img_ud;
uint32_t color = lua_tointeger(L, 2);
int iw = img->head.width;
@@ -227,16 +244,17 @@ int icelua_fn_common_img_free(lua_State *L)
{
int top = icelua_assert_stack(L, 1, 1);
- img_t *img = (img_t*)lua_touserdata(L, 1);
- if(img == NULL || img->udtype != UD_IMG)
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
return luaL_error(L, "not an image");
+ img_t **img_ud = (img_t**)lua_touserdata(L, 1);
+ if(img_ud == NULL || (*img_ud)->udtype != UD_IMG)
+ return luaL_error(L, "not an image");
+ img_t *img = *img_ud;
-#ifdef USE_OPENGL
- if(img->tex != 0)
- glDeleteTextures(1, &(img->tex));
-#endif
-
+#ifdef ALLOW_EXPLICIT_FREE
img_free(img);
+ *img_ud = NULL;
+#endif
return 0;
}
@@ -245,9 +263,12 @@ int icelua_fn_common_img_get_dims(lua_State *L)
{
int top = icelua_assert_stack(L, 1, 1);
- img_t *img = (img_t*)lua_touserdata(L, 1);
- if(img == NULL || img->udtype != UD_IMG)
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not an image");
+ img_t **img_ud = (img_t**)lua_touserdata(L, 1);
+ if(img_ud == NULL || (*img_ud)->udtype != UD_IMG)
return luaL_error(L, "not an image");
+ img_t *img = *img_ud;
lua_pushinteger(L, img->head.width);
lua_pushinteger(L, img->head.height);
View
52 src/lua_model.h
@@ -27,8 +27,8 @@ int icelua_fn_common_model_new(lua_State *L)
model_t *pmf = model_new(bonemax);
- // TODO: add this to a clean-up linked list or something
- lua_pushlightuserdata(L, pmf);
+ *(model_t **)lua_newuserdata(L, sizeof(void *)) = pmf;
+ model_gc_set(L);
return 1;
}
@@ -53,7 +53,9 @@ int icelua_fn_common_model_save_pmf(lua_State *L)
{
int top = icelua_assert_stack(L, 2, 2);
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t *pmf = *(model_t**)lua_touserdata(L, 1);
if(pmf == NULL)
return luaL_error(L, "not a model");
const char *fname = lua_tostring(L, 2);
@@ -79,11 +81,17 @@ int icelua_fn_common_model_free(lua_State *L)
{
int top = icelua_assert_stack(L, 1, 1);
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t **pmf_ud = (model_t**)lua_touserdata(L, 1);
+ model_t *pmf = *pmf_ud;
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
+#ifdef ALLOW_EXPLICIT_FREE
model_free(pmf);
+ *pmf_ud = NULL;
+#endif
return 0;
}
@@ -92,7 +100,9 @@ int icelua_fn_common_model_len(lua_State *L)
{
int top = icelua_assert_stack(L, 1, 1);
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t *pmf = *(model_t**)lua_touserdata(L, 1);
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
@@ -107,7 +117,10 @@ int icelua_fn_common_model_bone_new(lua_State *L)
int top = icelua_assert_stack(L, 1, 2);
int ptmax = 20;
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t **pmf_ud = (model_t**)lua_touserdata(L, 1);
+ model_t *pmf = *pmf_ud;
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
@@ -126,12 +139,13 @@ int icelua_fn_common_model_bone_new(lua_State *L)
csize = tsize;
pmf = model_extend(pmf, csize);
+ *pmf_ud = pmf;
}
// now add it
model_bone_t *bone = model_bone_new(pmf, ptmax);
- lua_pushlightuserdata(L, pmf);
+ lua_pushvalue(L, 1);
lua_pushinteger(L, bone->parent_idx);
return 2;
}
@@ -141,7 +155,9 @@ int icelua_fn_common_model_bone_free(lua_State *L)
int top = icelua_assert_stack(L, 1, 2);
int boneidx;
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t *pmf = *(model_t**)lua_touserdata(L, 1);
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
@@ -159,7 +175,9 @@ int icelua_fn_common_model_bone_get(lua_State *L)
int i;
int top = icelua_assert_stack(L, 2, 2);
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t *pmf = *(model_t**)lua_touserdata(L, 1);
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
@@ -208,7 +226,9 @@ int icelua_fn_common_model_bone_set(lua_State *L)
int i;
int top = icelua_assert_stack(L, 4, 4);
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t *pmf = *(model_t**)lua_touserdata(L, 1);
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
@@ -306,7 +326,9 @@ int icelua_fn_common_model_bone_find(lua_State *L)
int i;
int top = icelua_assert_stack(L, 2, 2);
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t *pmf = *(model_t**)lua_touserdata(L, 1);
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
@@ -337,7 +359,9 @@ int icelua_fn_client_model_render_bone_global(lua_State *L)
float ry, rx, ry2;
float scale;
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t *pmf = *(model_t**)lua_touserdata(L, 1);
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
@@ -373,7 +397,9 @@ int icelua_fn_client_model_render_bone_local(lua_State *L)
float ry, rx, ry2;
float scale;
- model_t *pmf = (model_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a model");
+ model_t *pmf = *(model_t**)lua_touserdata(L, 1);
if(pmf == NULL || pmf->udtype != UD_PMF)
return luaL_error(L, "not a model");
View
12 src/lua_wav.h
@@ -46,7 +46,9 @@ int icelua_fn_client_wav_play_global(lua_State *L)
{
int top = icelua_assert_stack(L, 4, 7);
- wav_t *wav = (wav_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a wav");
+ wav_t *wav = *(wav_t**)lua_touserdata(L, 1);
if(wav == NULL || wav->udtype != UD_WAV)
return luaL_error(L, "not a wav");
float x = lua_tonumber(L, 2);
@@ -77,7 +79,9 @@ int icelua_fn_client_wav_play_local(lua_State *L)
{
int top = icelua_assert_stack(L, 1, 7);
- wav_t *wav = (wav_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a wav");
+ wav_t *wav = *(wav_t**)lua_touserdata(L, 1);
if(wav == NULL || wav->udtype != UD_WAV)
return luaL_error(L, "not a wav");
float x = (top < 2 ? 0.0f : lua_tonumber(L, 2));
@@ -216,7 +220,9 @@ int icelua_fn_common_wav_free(lua_State *L)
{
int top = icelua_assert_stack(L, 1, 1);
- wav_t *wav = (wav_t*)lua_touserdata(L, 1);
+ if(lua_islightuserdata(L, 1) || !lua_isuserdata(L, 1))
+ return luaL_error(L, "not a wav");
+ wav_t *wav = *(wav_t**)lua_touserdata(L, 1);
if(wav == NULL || wav->udtype != UD_WAV)
return luaL_error(L, "not a wav");
View
23 src/model.c
@@ -47,6 +47,29 @@ void model_free(model_t *pmf)
free(pmf);
}
+int model_gc_lua(lua_State *L)
+{
+ model_t **pmf_ud = (model_t **)lua_touserdata(L, 1);
+ model_t *pmf = *pmf_ud;
+ if(pmf != NULL)
+ {
+#ifdef ALLOW_EXPLICIT_FREE
+ printf("Freeing pmf @ %p\n", pmf);
+#endif
+ model_free(pmf);
+ }
+
+ return 0;
+}
+
+void model_gc_set(lua_State *L)
+{
+ lua_newtable(L);
+ lua_pushcfunction(L, model_gc_lua);
+ lua_setfield(L, -2, "__gc");
+ lua_setmetatable(L, -2);
+}
+
model_bone_t *model_bone_new(model_t *pmf, int ptmax)
{
model_bone_t *bone = (model_bone_t*)malloc(sizeof(model_bone_t)+sizeof(model_point_t)*ptmax);
View
23 src/wav.c
@@ -415,6 +415,29 @@ void wav_kill(wav_t *wav)
}
}
+int wav_gc_lua(lua_State *L)
+{
+ wav_t **wav_ud = (wav_t **)lua_touserdata(L, 1);
+ wav_t *wav = *wav_ud;
+ if(wav != NULL)
+ {
+#ifdef ALLOW_EXPLICIT_FREE
+ printf("Freeing wav @ %p\n", wav);
+#endif
+ wav_kill(wav);
+ }
+
+ return 0;
+}
+
+void wav_gc_set(lua_State *L)
+{
+ lua_newtable(L);
+ lua_pushcfunction(L, wav_gc_lua);
+ lua_setfield(L, -2, "__gc");
+ lua_setmetatable(L, -2);
+}
+
#ifndef DEDI
int wav_init(void)
{

0 comments on commit 341c2f0

Please sign in to comment.
Something went wrong with that request. Please try again.