/* bi_model.c Ruamkoko model builtins Copyright (C) 2022 Bill Currie 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, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include "QF/model.h" #include "QF/progs.h" #include "rua_internal.h" typedef struct rua_model_s { struct rua_model_s *next; struct rua_model_s **prev; model_t *model; } rua_model_t; typedef struct { PR_RESMAP (rua_model_t) model_map; rua_model_t *handles; progs_t *pr; } rua_model_resources_t; static rua_model_t * rua_model_handle_new (rua_model_resources_t *res) { return PR_RESNEW (res->model_map); } static void rua_model_handle_free (rua_model_resources_t *res, rua_model_t *handle) { PR_RESFREE (res->model_map, handle); } static void rua_model_handle_reset (rua_model_resources_t *res) { PR_RESRESET (res->model_map); } static inline rua_model_t * __attribute__((pure)) rua__model_handle_get (rua_model_resources_t *res, int index, const char *name) { rua_model_t *handle = 0; handle = PR_RESGET(res->model_map, index); if (!handle) { PR_RunError (res->pr, "invalid model handle passed to %s", name + 3); } return handle; } #define rua_model_handle_get(res, index) \ rua__model_handle_get (res, index, __FUNCTION__) static inline int __attribute__((pure)) rua_model_handle_index (rua_model_resources_t *res, rua_model_t *handle) { return PR_RESINDEX(res->model_map, handle); } static void bi_rua_model_clear (progs_t *pr, void *_res) { rua_model_resources_t *res = (rua_model_resources_t *) _res; rua_model_t *handle; for (handle = res->handles; handle; handle = handle->next) Mod_UnloadModel (handle->model); res->handles = 0; rua_model_handle_reset (res); } static void bi_rua_model_destroy (progs_t *pr, void *_res) { } static int alloc_handle (rua_model_resources_t *res, model_t *model) { rua_model_t *handle = rua_model_handle_new (res); if (!handle) return 0; handle->next = res->handles; handle->prev = &res->handles; if (res->handles) res->handles->prev = &handle->next; res->handles = handle; handle->model = model; return rua_model_handle_index (res, handle); } static void bi_Model_Load (progs_t *pr, void *_res) { __auto_type res = (rua_model_resources_t *) _res; const char *path = P_GSTRING (pr, 0); model_t *model; R_INT (pr) = 0; if (!(model = Mod_ForName (path, 0))) return; if (!(R_INT (pr) = alloc_handle (res, model))) Mod_UnloadModel (model); } model_t * Model_GetModel (progs_t *pr, int handle) { if (!handle) { return 0; } rua_model_resources_t *res = PR_Resources_Find (pr, "Model"); rua_model_t *h = rua_model_handle_get (res, handle); return h->model; } static void bi_Model_Unload (progs_t *pr, void *_res) { __auto_type res = (rua_model_resources_t *) _res; int handle = P_INT (pr, 0); rua_model_t *h = rua_model_handle_get (res, handle); if (!h) PR_RunError (pr, "invalid model handle passed to Qclose"); Mod_UnloadModel (h->model); *h->prev = h->next; if (h->next) h->next->prev = h->prev; rua_model_handle_free (res, h); } #define bi(x,np,params...) {#x, bi_##x, -1, np, {params}} #define p(type) PR_PARAM(type) #define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), } static builtin_t builtins[] = { bi(Model_Load, 1, p(string)), bi(Model_Unload, 1, p(ptr)), {0} }; void RUA_Model_Init (progs_t *pr, int secure) { rua_model_resources_t *res = calloc (sizeof (rua_model_resources_t), 1); res->pr = pr; PR_Resources_Register (pr, "Model", res, bi_rua_model_clear, bi_rua_model_destroy); PR_RegisterBuiltins (pr, builtins, res); }