From 0539f07c1a51d0e071c8577fe1f00c7d077acb61 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 15 Jan 2024 02:26:24 +0900 Subject: [PATCH] [skin] Use an ECS registry to manage skins This takes care of the double free and also cleans up a lot of the skin api. However, the gl renderer lost top/bottom colors (for now). Vulkan skins still don't work yet. --- include/QF/plugin/vid_render.h | 5 +- include/QF/scene/entity.h | 29 +- include/QF/skin.h | 24 +- include/client/state.h | 2 +- include/mod_internal.h | 34 +- libs/client/cl_temp_entities.c | 2 - libs/client/cl_view.c | 1 - libs/models/alias/gl_model_alias.c | 5 - libs/models/gl_skin.c | 166 ++-------- libs/models/glsl_skin.c | 133 +++----- libs/models/skin.c | 366 +++++++++++----------- libs/models/sw_skin.c | 21 +- libs/scene/scene.c | 4 - libs/video/renderer/gl/gl_mod_alias.c | 18 +- libs/video/renderer/gl/gl_rmisc.c | 1 - libs/video/renderer/glsl/glsl_alias.c | 25 +- libs/video/renderer/sw/sw_ralias.c | 22 +- libs/video/renderer/sw/sw_riqm.c | 8 +- libs/video/renderer/vid_render_gl.c | 3 +- libs/video/renderer/vid_render_glsl.c | 3 +- libs/video/renderer/vid_render_sw.c | 3 +- libs/video/renderer/vid_render_vulkan.c | 12 - libs/video/renderer/vulkan/vulkan_alias.c | 10 +- nq/source/cl_ents.c | 12 +- nq/source/cl_parse.c | 6 - qw/source/cl_ents.c | 19 +- qw/source/cl_parse.c | 6 +- 27 files changed, 397 insertions(+), 543 deletions(-) diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 22b884c37..4eed08e2c 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -38,11 +38,11 @@ struct plitem_s; struct cvar_s; struct scene_s; -typedef struct skin_s skin_t; struct particle_s; struct mod_alias_ctx_s; struct mod_sprite_ctx_s; +typedef struct skin_s skin_t; struct entqueue_s; struct framebuffer_s; struct vrect_s; @@ -71,8 +71,7 @@ typedef struct vid_model_funcs_s { void (*Mod_SpriteLoadFrames) (struct mod_sprite_ctx_s *sprite_ctx); void (*skin_setupskin) (skin_t *skin, int cmap); - void (*skin_processtranslation) (int cmap, const byte *translation); - void (*skin_inittranslations) (void); + void (*skin_destroy) (skin_t *skin); } vid_model_funcs_t; struct tex_s; diff --git a/include/QF/scene/entity.h b/include/QF/scene/entity.h index 7438d60db..4629901bc 100644 --- a/include/QF/scene/entity.h +++ b/include/QF/scene/entity.h @@ -75,7 +75,7 @@ typedef struct visibility_s { typedef struct renderer_s { struct model_s *model; // NULL = no model - struct skin_s *skin; + uint32_t skin; struct trail_s *trail; unsigned fullbright:1; unsigned noshadows:1; @@ -117,6 +117,9 @@ ENTINLINE void EntQueue_AddEntity (entqueue_t *queue, entity_t ent, void EntQueue_Clear (entqueue_t *queue); ENTINLINE int Entity_Valid (entity_t ent); ENTINLINE transform_t Entity_Transform (entity_t ent); +ENTINLINE colormap_t *Entity_GetColormap (entity_t ent); +ENTINLINE void Entity_SetColormap (entity_t ent, colormap_t *colormap); +ENTINLINE void Entity_RemoveColormap (entity_t ent); #undef ENTINLINE #ifndef IMPLEMENT_ENTITY_Funcs @@ -157,6 +160,30 @@ Entity_Transform (entity_t ent) }; } +ENTINLINE +colormap_t * +Entity_GetColormap (entity_t ent) +{ + if (Ent_HasComponent (ent.id, ent.base + scene_colormap, ent.reg)) { + return Ent_GetComponent (ent.id, ent.base + scene_colormap, ent.reg); + } + return nullptr; +} + +ENTINLINE +void +Entity_SetColormap (entity_t ent, colormap_t *colormap) +{ + Ent_SetComponent (ent.id, ent.base + scene_colormap, ent.reg, colormap); +} + +ENTINLINE +void +Entity_RemoveColormap (entity_t ent) +{ + return Ent_RemoveComponent (ent.id, ent.base + scene_colormap, ent.reg); +} + struct mod_brush_s; efrag_t **R_LinkEfrag (struct mleaf_s *leaf, entity_t ent, uint32_t queue, efrag_t **lastlink); diff --git a/include/QF/skin.h b/include/QF/skin.h index d73753f08..e5892a85a 100644 --- a/include/QF/skin.h +++ b/include/QF/skin.h @@ -50,18 +50,20 @@ #define PLAYER_WIDTH 296 #define PLAYER_HEIGHT 194 -typedef struct skin_s { - const char *name; - bool valid; // the skin was found - struct tex_s *texels; - byte *colormap; - int texnum; - int auxtex; -} skin_t; +typedef struct ecs_registry_s ecs_registry_t; -void Skin_Free (skin_t *skin); -skin_t *Skin_SetColormap (skin_t *skin, int cmap); -skin_t *Skin_SetSkin (skin_t *skin, int cmap, const char *skinname); +enum { + skin_name, + skin_skin, + skin_colors, + + skin_comp_count +}; + +#define nullskin (0u) + +void Skin_Init (void); +uint32_t Skin_SetSkin (const char *skinname, int cmap); void Skin_SetTranslation (int cmap, int top, int bottom); #endif//__QF_skin_h diff --git a/include/client/state.h b/include/client/state.h index 46f0f8d88..24c3f54de 100644 --- a/include/client/state.h +++ b/include/client/state.h @@ -50,7 +50,7 @@ typedef struct player_info_s { int topcolor; int bottomcolor; struct info_key_s *skinname; - struct skin_s *skin; + uint32_t skin; entity_t flag_ent; diff --git a/include/mod_internal.h b/include/mod_internal.h index 803e6ebd4..a9ec0edb2 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -105,29 +105,37 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator); void Mod_LoadSpriteModel (model_t *mod, void *buffer); -void Skin_Init (void); -void Skin_Free (skin_t *skin); -skin_t *Skin_SetColormap (skin_t *skin, int cmap); -skin_t *Skin_SetSkin (skin_t *skin, int cmap, const char *skinname); -void Skin_SetTranslation (int cmap, int top, int bottom); int Skin_CalcTopColors (byte *out, const byte *in, size_t pixels, int stride); int Skin_CalcTopMask (byte *out, const byte *in, size_t pixels, int stride); int Skin_CalcBottomColors(byte *out, const byte *in, size_t pixels, int stride); int Skin_CalcBottomMask (byte *out, const byte *in, size_t pixels, int stride); int Skin_ClearTopColors (byte *out, const byte *in, size_t pixels); int Skin_ClearBottomColors (byte *out, const byte *in, size_t pixels); +void Skin_SetColormap (byte *dest, int top, int bottom); +void Skin_SetPalette (byte *dest, int top, int bottom); + +typedef struct tex_s tex_t; +typedef struct colormap_s colormap_t; + +tex_t *Skin_DupTex (const tex_t *tex); + +typedef struct skin_s { + tex_t *tex; + uint32_t id; + uint32_t fb; +} skin_t; + +skin_t *Skin_Get (uint32_t skin) __attribute__((pure)); void sw_Skin_SetupSkin (skin_t *skin, int cmap); -void sw_Skin_ProcessTranslation (int cmap, const byte *translation); -void sw_Skin_InitTranslations (void); +void sw_Skin_Destroy (skin_t *skin); +const byte *sw_Skin_Colormap (const colormap_t *colormap); void glsl_Skin_SetupSkin (skin_t *skin, int cmap); -void glsl_Skin_ProcessTranslation (int cmap, const byte *translation); -void glsl_Skin_InitTranslations (void); +void glsl_Skin_Destroy (skin_t *skin); +uint32_t glsl_Skin_Colormap (const colormap_t *colormap); void gl_Skin_SetupSkin (skin_t *skin, int cmap); -void gl_Skin_ProcessTranslation (int cmap, const byte *translation); -void gl_Skin_InitTranslations (void); -void gl_Skin_Init_Textures (void); -void gl_Skin_SetPlayerSkin (int width, int height, const byte *data); +void gl_Skin_Destroy (skin_t *skin); + #endif// __mod_internal_h diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index c1d3a11d7..4f13e44df 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -180,7 +180,6 @@ CL_Init_Entity (entity_t ent) *active = 1; *old_origin = (vec4f_t) {0, 0, 0, 1}; - renderer->skin = 0; QuatSet (1.0, 1.0, 1.0, 1.0, renderer->colormod); animation->pose1 = animation->pose2 = -1; } @@ -748,7 +747,6 @@ CL_ParseProjectiles (qmsg_t *net_message, bool nail2, TEntContext_t *ctx) pr = tent->ent; renderer_t *renderer = Ent_GetComponent (pr.id, pr.base + scene_renderer, pr.reg); renderer->model = cl_spike; - renderer->skin = 0; position[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; position[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096; position[2] = ((bits[3] + ((bits[4] & 15) << 8)) << 1) - 4096; diff --git a/libs/client/cl_view.c b/libs/client/cl_view.c index ff0718aea..ab6ce57f7 100644 --- a/libs/client/cl_view.c +++ b/libs/client/cl_view.c @@ -870,7 +870,6 @@ V_CalcRefdef (viewstate_t *vs) } renderer->model = model; animation->frame = vs->weaponframe; - renderer->skin = 0; // set up the refresh position rotation = Transform_GetWorldRotation (vs->camera_transform); diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index 96f3b26fa..9e824177c 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -70,11 +70,6 @@ gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *texels, dstring_t *name = dstring_new (); Mod_FloodFillSkin (texels, header->mdl.skinwidth, header->mdl.skinheight); - // save 8 bit texels for the player model to remap - // FIXME remove model restriction - if (strequal (alias_ctx->mod->path, "progs/player.mdl")) - gl_Skin_SetPlayerSkin (header->mdl.skinwidth, header->mdl.skinheight, - texels); QFS_StripExtension (alias_ctx->mod->path, modname); diff --git a/libs/models/gl_skin.c b/libs/models/gl_skin.c index b8b17c5e8..90bd2b9a3 100644 --- a/libs/models/gl_skin.c +++ b/libs/models/gl_skin.c @@ -54,50 +54,8 @@ #include "mod_internal.h" #include "r_internal.h" -typedef struct { - tex_t *tex; - tex_t *fb_tex; - bool fb; -} glskin_t; - -static GLuint skin_textures[MAX_TRANSLATIONS]; -static GLuint skin_fb_textures[MAX_TRANSLATIONS]; -static byte skin_cmap[MAX_TRANSLATIONS][256]; - -static glskin_t skins[MAX_TRANSLATIONS]; -static glskin_t player_skin; - -static void -do_fb_skin (glskin_t *s) -{ - int size = s->tex->width * s->tex->height; - - s->fb_tex = realloc (s->fb_tex, sizeof (tex_t) + size); - s->fb_tex->data = (byte *) (s->fb_tex + 1); - s->fb_tex->width = s->tex->width; - s->fb_tex->height = s->tex->height; - s->fb_tex->format = tex_palette; - s->fb_tex->palette = vid.palette; - s->fb = Mod_CalcFullbright (s->fb_tex->data, s->tex->data, size); -} - -void -gl_Skin_SetPlayerSkin (int width, int height, const byte *data) -{ - int size = width * height; - glskin_t *s; - - s = &player_skin; - s->tex = realloc (s->tex, sizeof (tex_t) + size); - s->tex->data = (byte *) (s->tex + 1); - s->tex->width = width; - s->tex->height = height; - s->tex->format = tex_palette; - s->tex->palette = vid.palette; - memcpy (s->tex->data, data, size); - - do_fb_skin (s); -} +// FIXME colormap (top/bottom colors) +//static byte skin_cmap[MAX_TRANSLATIONS][256]; static void build_skin_8 (tex_t *tex, int texnum, byte *translate, @@ -150,7 +108,7 @@ build_skin_32 (tex_t *tex, int texnum, byte *translate, *out++ = *pal++; *out++ = *pal++; *out++ = *pal++; - *out++ = (alpha && c == 255) ? 0 : 255; + *out++ = (alpha && c == 0) ? 0 : 255; frac += fracstep; } } @@ -166,103 +124,41 @@ build_skin_32 (tex_t *tex, int texnum, byte *translate, gl_aniso); } -static void -build_skin (skin_t *skin, int cmap) -{ - glskin_t *s; - unsigned scaled_width, scaled_height; - int texnum, fb_texnum; - - // FIXME deek: This 512x256 limit sucks! - scaled_width = min (gl_max_size, 512); - scaled_height = min (gl_max_size, 256); - - // allow users to crunch sizes down even more if they want - scaled_width >>= gl_playermip; - scaled_height >>= gl_playermip; - scaled_width = max (scaled_width, 1); - scaled_height = max (scaled_height, 1); - - s = skins + cmap; - if (!s->tex) - s = &player_skin; - if (!s->tex) // we haven't loaded the player model yet - return; - - texnum = skin_textures[cmap]; - fb_texnum = 0; - if (s->fb) - fb_texnum = skin_fb_textures[cmap]; - if (skin) { - skin->texnum = texnum; - skin->auxtex = fb_texnum; - } - if (vid.is8bit) { - build_skin_8 (s->tex, texnum, skin_cmap[cmap], - scaled_width, scaled_height, false); - if (s->fb && s->fb_tex) - build_skin_8 (s->fb_tex, fb_texnum, skin_cmap[cmap], - scaled_width, scaled_height, true); - } else { - build_skin_32 (s->tex, texnum, skin_cmap[cmap], - scaled_width, scaled_height, false); - if (s->fb && s->fb_tex) - build_skin_32 (s->fb_tex, fb_texnum, skin_cmap[cmap], - scaled_width, scaled_height, true); - } -} - -void -gl_Skin_ProcessTranslation (int cmap, const byte *translation) -{ - int changed; - - // simplify cmap usage (texture offset/array index) - cmap--; - // skip over the colormap (GL can't use it) to the translated palette - translation += VID_GRADES * 256; - changed = memcmp (skin_cmap[cmap], translation, 256); - memcpy (skin_cmap[cmap], translation, 256); - if (!changed) - return; - build_skin (0, cmap); -} - void gl_Skin_SetupSkin (skin_t *skin, int cmap) { - int changed; - glskin_t *s; + //skin->tex = Skin_DupTex (skin->tex); + tex_t *tex = skin->tex; + skin->tex = nullptr; // tex memory is only temporarily allocated - skin->texnum = 0; - skin->auxtex = 0; - if (!cmap) { - return; + auto build_skin = vid.is8bit ? build_skin_8 : build_skin_32; + + unsigned swidth = min (gl_max_size, 512); + unsigned sheight = min (gl_max_size, 256); + // allow users to crunch sizes down even more if they want + swidth >>= gl_playermip; + sheight >>= gl_playermip; + swidth = max (swidth, 1); + sheight = max (sheight, 1); + + int size = tex->width * tex->height; + byte fbskin[size]; + qfglGenTextures (1, &skin->id); + // FIXME colormap (top/bottom colors) + build_skin_32 (tex, skin->id, vid.colormap8, swidth, sheight, false); + if (Mod_CalcFullbright (fbskin, tex->data, size)) { + tex_t fb_tex = *tex; + fb_tex.data = fbskin; + qfglGenTextures (1, &skin->fb); + build_skin (&fb_tex, skin->fb, vid.colormap8, swidth, sheight, true); } - // simplify cmap usage (texture offset/array index) - cmap--; - s = skins + cmap; - changed = (s->tex != skin->texels); - s->tex = skin->texels; - if (!changed) { - skin->texnum = skin_textures[cmap]; - if (s->fb) - skin->auxtex = skin_fb_textures[cmap]; - return; - } - if (s->tex) - do_fb_skin (s); - build_skin (skin, cmap); } void -gl_Skin_InitTranslations (void) +gl_Skin_Destroy (skin_t *skin) { -} - -void -gl_Skin_Init_Textures (void) -{ - qfglGenTextures (MAX_TRANSLATIONS, skin_textures); - qfglGenTextures (MAX_TRANSLATIONS, skin_fb_textures); + qfglDeleteTextures (1, &skin->id); + if (skin->fb) { + qfglDeleteTextures (1, &skin->fb); + } } diff --git a/libs/models/glsl_skin.c b/libs/models/glsl_skin.c index 8e6d74878..6393fac78 100644 --- a/libs/models/glsl_skin.c +++ b/libs/models/glsl_skin.c @@ -51,99 +51,60 @@ #include "mod_internal.h" #include "r_internal.h" -static GLuint cmap_tex[MAX_TRANSLATIONS]; -static GLuint skin_tex[MAX_TRANSLATIONS]; -void -glsl_Skin_ProcessTranslation (int cmap, const byte *translation) +static GLuint colormaps[256]; + +uint32_t +glsl_Skin_Colormap (const colormap_t *colormap) { - byte top[4 * VID_GRADES * 16]; - byte bottom[4 * VID_GRADES * 16]; - const byte *src; - byte *dst; - int i, j; - - src = translation + TOP_RANGE; - for (i = 0, dst = top; i < VID_GRADES; i++, src += 256 - 16) { - for (j = 0; j < 16; j++) { - byte c = *src++; - const byte *in = vid.palette + c * 3; - *dst++ = *in++; - *dst++ = *in++; - *dst++ = *in++; - *dst++ = 255; // alpha = 1 - } + byte top = colormap->top & 0x0f; + byte bot = colormap->bottom & 0x0f; + int ind = top | (bot << 4); + if (colormaps[ind]) { + return colormaps[ind]; } - src = translation + BOTTOM_RANGE; - for (i = 0, dst = bottom; i < VID_GRADES; i++, src += 256 - 16) { - for (j = 0; j < 16; j++) { - byte c = *src++; - const byte *in = vid.palette + c * 3; - *dst++ = *in++; - *dst++ = *in++; - *dst++ = *in++; - *dst++ = 255; // alpha = 1 - } - } - qfeglBindTexture (GL_TEXTURE_2D, cmap_tex[cmap - 1]); - qfeglTexSubImage2D (GL_TEXTURE_2D, 0, TOP_RANGE, 0, 16, VID_GRADES, - GL_RGBA, GL_UNSIGNED_BYTE, top); - qfeglTexSubImage2D (GL_TEXTURE_2D, 0, BOTTOM_RANGE, 0, 16, VID_GRADES, - GL_RGBA, GL_UNSIGNED_BYTE, bottom); -} - -void -glsl_Skin_SetupSkin (skin_t *skin, int cmap) -{ - skin->texnum = 0; - if (cmap) { - if (skin->texels) { - tex_t *tex = skin->texels; - - skin->texnum = skin_tex[cmap - 1]; - qfeglBindTexture (GL_TEXTURE_2D, skin->texnum); - qfeglTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, - tex->width, tex->height, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, tex->data); - qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_NEAREST); - qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - GL_NEAREST); - } - skin->auxtex = cmap_tex[cmap - 1]; - } else { - skin->auxtex = 0; - } -} - -void -glsl_Skin_InitTranslations (void) -{ - byte map[4 * VID_GRADES * 256]; - byte *src, *dst; - int i; - - for (i = 0, dst = map, src = vid.colormap8; i < 256 * VID_GRADES; i++) { + qfeglGenTextures (1, &colormaps[ind]); + byte cmap[4 * VID_GRADES * 256]; + byte *dst = cmap; + byte *src = cmap + 3 * VID_GRADES * 256; + Skin_SetColormap (src, top, bot); + for (int i = 0; i < VID_GRADES * 256; i++) { byte c = *src++; const byte *in = vid.palette + c * 3; *dst++ = *in++; *dst++ = *in++; *dst++ = *in++; - *dst++ = 255; // alpha = 1 - } - qfeglGenTextures (MAX_TRANSLATIONS, cmap_tex); - qfeglGenTextures (MAX_TRANSLATIONS, skin_tex); - for (i = 0; i < MAX_TRANSLATIONS; i++) { - qfeglBindTexture (GL_TEXTURE_2D, cmap_tex[i]); - qfeglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 256, VID_GRADES, 0, - GL_RGBA, GL_UNSIGNED_BYTE, map); - qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + *dst++ = 255; } + + qfeglBindTexture (GL_TEXTURE_2D, colormaps[ind]); + qfeglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 256, VID_GRADES, 0, + GL_RGBA, GL_UNSIGNED_BYTE, cmap); + qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + return colormaps[ind]; +} + +void +glsl_Skin_SetupSkin (skin_t *skin, int cmap) +{ + tex_t *tex = skin->tex; + skin->tex = nullptr; // tex memory is only temporarily allocated + + qfeglGenTextures (1, &skin->id); + qfeglBindTexture (GL_TEXTURE_2D, skin->id); + qfeglTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, tex->width, tex->height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, tex->data); + qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + +void +glsl_Skin_Destroy (skin_t *skin) +{ + qfeglDeleteTextures (1, &skin->id); } diff --git a/libs/models/skin.c b/libs/models/skin.c index 38007583f..312810115 100644 --- a/libs/models/skin.c +++ b/libs/models/skin.c @@ -40,6 +40,7 @@ #include +#include "QF/ecs.h" #include "QF/hash.h" #include "QF/image.h" #include "QF/model.h" @@ -52,206 +53,176 @@ #include "mod_internal.h" -typedef struct skinbank_s { - char *name; - tex_t *texels; - int users; -} skinbank_t; - vid_model_funcs_t *m_funcs; -// each translation has one extra line for palette (vs colormap) based -// translation (for 32bit rendering) -static byte translations[MAX_TRANSLATIONS][(VID_GRADES + 1) * 256]; -static hashtab_t *skin_cache; - -static skin_t * -new_skin (void) +static void +skin_name_destroy (void *_name, ecs_registry_t *reg) { - return calloc (1, sizeof (skin_t)); -} - -VISIBLE void -Skin_Free (skin_t *skin) -{ - if (skin) { - free (skin); - } -} - -VISIBLE void -Skin_SetTranslation (int cmap, int top, int bottom) -{ - int i, j; - byte *source; - byte *dest; - - if (!cmap) // 0 is meant for no custom mapping. this just makes - return; // other code simpler - top = bound (0, top, 13) * 16; - bottom = bound (0, bottom, 13) * 16; - - if (cmap < 0 || cmap > MAX_TRANSLATIONS) { - Sys_MaskPrintf (SYS_skin, "invalid skin slot: %d\n", cmap); - cmap = 1; - } - - dest = translations[cmap - 1]; - source = r_data->vid->colormap8; - memcpy (dest, source, VID_GRADES * 256); - - for (i = 0; i < VID_GRADES; i++, dest += 256, source += 256) { - if (top < 128) // the artists made some backwards ranges. - memcpy (dest + TOP_RANGE, source + top, 16); - else - for (j = 0; j < 16; j++) - dest[TOP_RANGE + j] = source[top + 15 - j]; - - if (bottom < 128) - memcpy (dest + BOTTOM_RANGE, source + bottom, 16); - else - for (j = 0; j < 16; j++) - dest[BOTTOM_RANGE + j] = source[bottom + 15 - j]; - } - // set up the palette translation - // dest currently points to the palette line - for (i = 0; i < 256; i++) - dest[i] = i; - for (i = 0; i < 16; i++) { - if (top < 128) - dest[TOP_RANGE + i] = top + i; - else - dest[TOP_RANGE + i] = top + 15 - i; - if (bottom < 128) - dest[BOTTOM_RANGE + i] = bottom + i; - else - dest[BOTTOM_RANGE + i] = bottom + 15 - i; - } - m_funcs->skin_processtranslation (cmap, translations[cmap - 1]); -} - -skin_t * -Skin_SetColormap (skin_t *skin, int cmap) -{ - if (!skin) - skin = new_skin (); - skin->colormap = 0; - if (cmap < 0 || cmap > MAX_TRANSLATIONS) { - Sys_MaskPrintf (SYS_skin, "invalid skin slot: %d\n", cmap); - cmap = 0; - } - if (cmap) - skin->colormap = translations[cmap - 1]; - m_funcs->skin_setupskin (skin, cmap); - return skin; -} - -skin_t * -Skin_SetSkin (skin_t *skin, int cmap, const char *skinname) -{ - char *name = 0; - skinbank_t *sb = 0; - tex_t *tex = 0; - - if (skinname) { - name = QFS_CompressPath (skinname); - QFS_StripExtension (name, name); - if (strchr (name, '.') || strchr (name, '/')) { - Sys_Printf ("Bad skin name: '%s'\n", skinname); - free (name); - name = 0; - } - } - - do { - QFile *file; - byte *ipix, *opix; - int i; - tex_t *out; - - if (!name) - break; - sb = Hash_Find (skin_cache, name); - if (sb) { - sb->users++; - tex = sb->texels; - break; - } - - if (Hash_NumElements (skin_cache) >= MAX_CACHED_SKINS) { - Sys_Printf ("Too many skins\n"); - free (name); - name = 0; - break; - } - - file = QFS_FOpenFile (va (0, "skins/%s.pcx", name)); - if (!file) { - Sys_Printf ("Couldn't load skin %s\n", name); - free (name); - name = 0; - break; - } - tex = LoadPCX (file, 0, r_data->vid->palette, 1); - Qclose (file); - if (!tex || tex->width > 320 || tex->height > 200) { - Sys_Printf ("Bad skin %s\n", name); - free (name); - name = 0; - tex = 0; - break; - } - out = malloc (sizeof (tex_t) + PLAYER_WIDTH*PLAYER_HEIGHT); - out->data = (byte *) (out + 1); - out->width = PLAYER_WIDTH; - out->height = PLAYER_HEIGHT; - out->format = tex_palette; - out->palette = r_data->vid->palette; - memset (out->data, 0, PLAYER_WIDTH * PLAYER_HEIGHT); - opix = out->data; - ipix = tex->data; - for (i = 0; i < out->height; i++) { - memcpy (opix, ipix, min (tex->width, out->width)); - ipix += tex->width; - opix += out->width; - } - tex = out; - - sb = malloc (sizeof (skinbank_t)); - sb->texels = tex; - sb->name = name; - sb->users = 1; - Hash_Add (skin_cache, sb); - } while (0); - - if (!skin) - skin = new_skin (); - skin->texels = tex; - skin->name = name; - m_funcs->skin_setupskin (skin, cmap); - return skin; -} - -static const char * -skin_getkey (const void *sb, void *unused) -{ - return ((skinbank_t *) sb)->name; + char **name = _name; + free (*name); } static void -skin_free (void *_sb, void *unused) +skin_destroy (void *_skin, ecs_registry_t *reg) { - skinbank_t *sb = (skinbank_t *) _sb; + skin_t *skin = _skin; + if (m_funcs->skin_destroy) { + m_funcs->skin_destroy (skin); + } +} - free (sb->name); - free (sb->texels); - free (sb); +static const component_t skin_components[skin_comp_count] = { + [skin_name] = { + .size = sizeof (char *), + .name = "skin name", + .destroy = skin_name_destroy, + }, + [skin_skin] = { + .size = sizeof (skin_t), + .name = "skin", + .destroy = skin_destroy, + }, + [skin_colors] = { + }, +}; + +static hashtab_t *skin_hash; +static ecs_system_t skinsys; + +VISIBLE void +Skin_SetColormap (byte *dest, int top, int bottom) +{ + byte *source; + + top = bound (0, top, 13) * 16; + bottom = bound (0, bottom, 13) * 16; + + source = r_data->vid->colormap8; + memcpy (dest, source, VID_GRADES * 256); + + for (int i = 0; i < VID_GRADES; i++, dest += 256, source += 256) { + if (top < 128) { + memcpy (dest + TOP_RANGE, source + top, 16); + } else { + // the artists made some backwards ranges. + for (int j = 0; j < 16; j++) { + dest[TOP_RANGE + j] = source[top + 15 - j]; + } + } + + if (bottom < 128) { + memcpy (dest + BOTTOM_RANGE, source + bottom, 16); + } else { + for (int j = 0; j < 16; j++) { + dest[BOTTOM_RANGE + j] = source[bottom + 15 - j]; + } + } + } +} + +VISIBLE void +Skin_SetPalette (byte *dest, int top, int bottom) +{ + for (int i = 0; i < 256; i++) { + dest[i] = i; + } + for (int i = 0; i < 16; i++) { + if (top < 128) { + dest[TOP_RANGE + i] = top + i; + } else { + dest[TOP_RANGE + i] = top + 15 - i; + } + if (bottom < 128) { + dest[BOTTOM_RANGE + i] = bottom + i; + } else { + dest[BOTTOM_RANGE + i] = bottom + 15 - i; + } + } +} + +static void +freestr (char **strptr) +{ + free (*strptr); +} + +VISIBLE uint32_t +Skin_SetSkin (const char *skinname, int cmap) +{ + if (!skinname || !*skinname) { + return nullskin; + } + __attribute__((cleanup (freestr))) char *name = QFS_CompressPath (skinname); + QFS_StripExtension (name, name); + if (strchr (name, '.') || strchr (name, '/')) { + Sys_Printf ("Bad skin name: '%s'\n", skinname); + return nullskin; + } + void *_id = Hash_Find (skin_hash, name); + if (_id) { + return (uint32_t) (uintptr_t) _id; + } + + // always create a new skin entity so the name can be associated with + // a possibly bad skin (to prevent unnecessary retries) + uint32_t skinent = ECS_NewEntity (skinsys.reg); + char *sname = strdup (name); + Ent_SetComponent (skinent, skinsys.base + skin_name, skinsys.reg, &sname); + Hash_Add (skin_hash, (void *) (uintptr_t) skinent); + + QFile *file = QFS_FOpenFile (va (0, "skins/%s.pcx", name)); + if (!file) { + Sys_Printf ("Couldn't load skin %s\n", name); + return skinent; + } + tex_t *tex = LoadPCX (file, 0, r_data->vid->palette, 1); + Qclose (file); + if (!tex) { + Sys_Printf ("Bad skin %s\n", name); + return skinent; + } + + skin_t skin = { + .tex = tex, + }; + m_funcs->skin_setupskin (&skin, cmap); + Ent_SetComponent (skinent, skinsys.base + skin_skin, skinsys.reg, &skin); + + return skinent; +} + +skin_t * +Skin_Get (uint32_t skin) +{ + if (ECS_EntValid (skin, skinsys.reg) + && Ent_HasComponent (skin, skinsys.base + skin_skin, skinsys.reg)) { + return Ent_GetComponent (skin, skinsys.base + skin_skin, skinsys.reg); + } + return nullptr; +} + +static const char * +skin_getkey (const void *_id, void *_sys) +{ + uint32_t id = (uint32_t) (uintptr_t) _id; + auto sys = (ecs_system_t *) _sys; + char **name = Ent_GetComponent (id, sys->base + skin_name, sys->reg); + return *name; +} + +static void +skin_free (void *_id, void *_sys) +{ + uint32_t id = (uint32_t) (uintptr_t) _id; + auto sys = (ecs_system_t *) _sys; + ECS_DelEntity (sys->reg, id); } static void skin_shutdown (void *data) { - Hash_DelTable (skin_cache); + Hash_DelTable (skin_hash); + ECS_DelRegistry (skinsys.reg); } void @@ -259,8 +230,14 @@ Skin_Init (void) { qfZoneScoped (true); Sys_RegisterShutdown (skin_shutdown, 0); - skin_cache = Hash_NewTable (127, skin_getkey, skin_free, 0, 0); - m_funcs->skin_inittranslations (); + skin_hash = Hash_NewTable (127, skin_getkey, skin_free, &skinsys, 0); + auto reg = ECS_NewRegistry ("skins"); + skinsys = (ecs_system_t) { + .reg = reg, + .base = ECS_RegisterComponents (reg, skin_components, skin_comp_count), + }; + ECS_CreateComponentPools (reg); + ECS_NewEntity (reg); // reserve entity 0 } VISIBLE int @@ -362,3 +339,14 @@ Skin_ClearBottomColors (byte *out, const byte *in, size_t pixels) } return 0; } + +VISIBLE tex_t * +Skin_DupTex (const tex_t *tex) +{ + int size = tex->width * tex->height; + tex_t *dup = malloc (sizeof (tex_t) + size); + *dup = *tex; + dup->data = (byte *) (dup + 1); + memcpy (dup->data, tex->data, size); + return dup; +} diff --git a/libs/models/sw_skin.c b/libs/models/sw_skin.c index 2b88d6715..bcd8d41c2 100644 --- a/libs/models/sw_skin.c +++ b/libs/models/sw_skin.c @@ -31,19 +31,34 @@ # include "config.h" #endif +#include "QF/image.h" + #include "mod_internal.h" -void -sw_Skin_ProcessTranslation (int cmap, const byte *translation) +static byte *colormaps[256]; + +const byte * +sw_Skin_Colormap (const colormap_t *colormap) { + byte top = colormap->top & 0x0f; + byte bot = colormap->bottom & 0x0f; + int ind = top | (bot << 4); + if (colormaps[ind]) { + return colormaps[ind]; + } + colormaps[ind] = malloc (VID_GRADES * 256); + Skin_SetColormap (colormaps[ind], top, bot); + return colormaps[ind]; } void sw_Skin_SetupSkin (skin_t *skin, int cmap) { + skin->tex = Skin_DupTex (skin->tex); } void -sw_Skin_InitTranslations (void) +sw_Skin_Destroy (skin_t *skin) { + free (skin->tex); } diff --git a/libs/scene/scene.c b/libs/scene/scene.c index 9c64c561c..a96f7b80b 100644 --- a/libs/scene/scene.c +++ b/libs/scene/scene.c @@ -80,10 +80,6 @@ destroy_visibility (void *_visibility, ecs_registry_t *reg) static void destroy_renderer (void *_renderer, ecs_registry_t *reg) { - renderer_t *renderer = _renderer; - if (renderer->skin) { - Skin_Free (renderer->skin); - } } static void diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index 5e30ad8bb..2b5aa3964 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -52,6 +52,7 @@ #include "QF/GL/qf_vid.h" #include "compat.h" +#include "mod_internal.h" #include "r_internal.h" #include "vid_gl.h" @@ -407,7 +408,7 @@ gl_R_DrawAliasModel (entity_t e) color[4] = {0.0, 0.0, 0.0, 1.0}, dark[4] = {0.0, 0.0, 0.0, 1.0}, emission[4] = {0.0, 0.0, 0.0, 1.0}; - int gl_light, texture; + int gl_light, texture = 0; int fb_texture = 0, used_lights = 0; bool is_fullbright = false; aliashdr_t *paliashdr; @@ -557,14 +558,17 @@ gl_R_DrawAliasModel (entity_t e) // if the model has a colorised/external skin, use it, otherwise use // the skin embedded in the model data - if (renderer->skin && renderer->skin->texnum && !gl_nocolors) { - skin_t *skin = renderer->skin; + if (renderer->skin && !gl_nocolors) { + skin_t *skin = Skin_Get (renderer->skin); - texture = skin->texnum; - if (gl_fb_models) { - fb_texture = skin->auxtex; + if (skin) { + texture = skin->id; + if (gl_fb_models) { + fb_texture = skin->fb; + } } - } else { + } + if (!texture) { maliasskindesc_t *skindesc; animation_t *animation = Ent_GetComponent (e.id, e.base + scene_animation, e.reg); diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index f8fdf4b7e..aa139f4f4 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -134,7 +134,6 @@ gl_R_Init (void) GDT_Init (); gl_R_InitGraphTextures (); - gl_Skin_Init_Textures (); r_init = 1; gl_R_InitParticles (); diff --git a/libs/video/renderer/glsl/glsl_alias.c b/libs/video/renderer/glsl/glsl_alias.c index 40e5b8f19..79d6aefd8 100644 --- a/libs/video/renderer/glsl/glsl_alias.c +++ b/libs/video/renderer/glsl/glsl_alias.c @@ -52,6 +52,7 @@ #include "QF/GLSL/qf_textures.h" #include "QF/GLSL/qf_vid.h" +#include "mod_internal.h" #include "r_internal.h" #define s_dynlight (r_refdef.scene->base + scene_dynlight) @@ -235,8 +236,6 @@ glsl_R_DrawAlias (entity_t ent) float blend; aliashdr_t *hdr; vec_t norm_mat[9]; - int skin_tex; - int colormap; aliasvrt_t *pose1 = 0; // VBO's are null based aliasvrt_t *pose2 = 0; // VBO's are null based mat4f_t worldMatrix; @@ -271,13 +270,19 @@ glsl_R_DrawAlias (entity_t ent) animation_t *animation = Ent_GetComponent (ent.id, ent.base + scene_animation, ent.reg); - colormap = glsl_colormap; - if (renderer->skin && renderer->skin->auxtex) - colormap = renderer->skin->auxtex; - if (renderer->skin && renderer->skin->texnum) { - skin_t *skin = renderer->skin; - skin_tex = skin->texnum; - } else { + GLuint cmap_tex = glsl_colormap; + auto colormap = Entity_GetColormap (ent); + if (colormap) { + cmap_tex = glsl_Skin_Colormap (colormap); + } + GLuint skin_tex = 0; + if (renderer->skin) { + skin_t *skin = Skin_Get (renderer->skin); + if (skin) { + skin_tex = skin->id; + } + } + if (!skin_tex) { maliasskindesc_t *skindesc; skindesc = R_AliasGetSkindesc (animation, renderer->skinnum, hdr); skin_tex = skindesc->texnum; @@ -291,7 +296,7 @@ glsl_R_DrawAlias (entity_t ent) skin_size[1] = hdr->mdl.skinheight; qfeglActiveTexture (GL_TEXTURE0 + 1); - qfeglBindTexture (GL_TEXTURE_2D, colormap); + qfeglBindTexture (GL_TEXTURE_2D, cmap_tex); qfeglActiveTexture (GL_TEXTURE0 + 0); qfeglBindTexture (GL_TEXTURE_2D, skin_tex); diff --git a/libs/video/renderer/sw/sw_ralias.c b/libs/video/renderer/sw/sw_ralias.c index d8de21787..f9d49eb9b 100644 --- a/libs/video/renderer/sw/sw_ralias.c +++ b/libs/video/renderer/sw/sw_ralias.c @@ -39,6 +39,7 @@ #include "QF/scene/entity.h" #include "d_ifacea.h" +#include "mod_internal.h" #include "r_internal.h" #define LIGHT_MIN 5 // lowest light value we'll allow, to @@ -555,17 +556,15 @@ R_AliasSetupSkin (entity_t ent) r_affinetridesc.seamfixupX16 = (a_skinwidth >> 1) << 16; r_affinetridesc.skinheight = pmdl->skinheight; - acolormap = r_colormap; if (renderer->skin) { - tex_t *base; + auto skin = Skin_Get (renderer->skin); - base = renderer->skin->texels; - if (base) { - r_affinetridesc.pskin = base->data; - r_affinetridesc.skinwidth = base->width; - r_affinetridesc.skinheight = base->height; + if (skin) { + tex_t *tex = skin->tex; + r_affinetridesc.pskin = tex->data; + r_affinetridesc.skinwidth = tex->width; + r_affinetridesc.skinheight = tex->height; } - acolormap = renderer->skin->colormap; } } @@ -657,8 +656,11 @@ R_AliasDrawModel (entity_t ent, alight_t *lighting) r_affinetridesc.drawtype = ((visibility->trivial_accept == 3) && r_recursiveaffinetriangles); - if (!acolormap) - acolormap = r_colormap; + acolormap = r_colormap; + auto cmap = Entity_GetColormap (ent); + if (cmap) { + acolormap = sw_Skin_Colormap (cmap); + } if (r_affinetridesc.drawtype) { D_PolysetUpdateTables (); // FIXME: precalc... diff --git a/libs/video/renderer/sw/sw_riqm.c b/libs/video/renderer/sw/sw_riqm.c index 9ba26d2c9..97e9810e1 100644 --- a/libs/video/renderer/sw/sw_riqm.c +++ b/libs/video/renderer/sw/sw_riqm.c @@ -48,6 +48,7 @@ #include "QF/scene/entity.h" #include "d_ifacea.h" +#include "mod_internal.h" #include "r_internal.h" #ifdef PIC @@ -322,8 +323,11 @@ R_IQMDrawModel (entity_t ent, alight_t *plighting) r_affinetridesc.drawtype = (visibility->trivial_accept == 3) && r_recursiveaffinetriangles; - //if (!acolormap) - acolormap = r_colormap; + acolormap = r_colormap; + auto cmap = Entity_GetColormap (ent); + if (cmap) { + acolormap = sw_Skin_Colormap (cmap); + } //FIXME depth hack if (ent.id != vr_data.view_model.id) diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 3188f7c93..35c299fcc 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -172,8 +172,7 @@ static vid_model_funcs_t model_funcs = { .Mod_SpriteLoadFrames = gl_Mod_SpriteLoadFrames, .skin_setupskin = gl_Skin_SetupSkin, - .skin_processtranslation = gl_Skin_ProcessTranslation, - .skin_inittranslations = gl_Skin_InitTranslations, + .skin_destroy = gl_Skin_Destroy, }; static void diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 5c5d1ad68..057072874 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -83,8 +83,7 @@ static vid_model_funcs_t model_funcs = { .Mod_SpriteLoadFrames = glsl_Mod_SpriteLoadFrames, .skin_setupskin = glsl_Skin_SetupSkin, - .skin_processtranslation = glsl_Skin_ProcessTranslation, - .skin_inittranslations = glsl_Skin_InitTranslations, + .skin_destroy = glsl_Skin_Destroy, }; static void diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index cfccfab81..769cc749a 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -92,8 +92,7 @@ static vid_model_funcs_t model_funcs = { .Mod_SpriteLoadFrames = sw_Mod_SpriteLoadFrames, .skin_setupskin = sw_Skin_SetupSkin, - .skin_processtranslation = sw_Skin_ProcessTranslation, - .skin_inittranslations = sw_Skin_InitTranslations, + .skin_destroy = sw_Skin_Destroy, }; static void diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index fd961a828..acdc2bd09 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -456,16 +456,6 @@ vulkan_Skin_SetupSkin (struct skin_s *skin, int cmap) { } -static void -vulkan_Skin_ProcessTranslation (int cmap, const byte *translation) -{ -} - -static void -vulkan_Skin_InitTranslations (void) -{ -} - static void set_palette (void *data, const byte *palette) { @@ -524,8 +514,6 @@ static vid_model_funcs_t model_funcs = { .Mod_SpriteLoadFrames = vulkan_Mod_SpriteLoadFrames, .skin_setupskin = vulkan_Skin_SetupSkin, - .skin_processtranslation = vulkan_Skin_ProcessTranslation, - .skin_inittranslations = vulkan_Skin_InitTranslations, }; static void diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 762dc2299..ee886817d 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -79,12 +79,6 @@ alias_get_animation (entity_t ent) return Ent_GetComponent (ent.id, ent.base + scene_animation, ent.reg); } -static colormap_t * -alias_get_colormap (entity_t ent) -{ - return Ent_GetComponent (ent.id, ent.base + scene_colormap, ent.reg); -} - static void alias_depth_range (qfv_taskctx_t *taskctx, float minDepth, float maxDepth) { @@ -206,8 +200,8 @@ alias_draw_ent (qfv_taskctx_t *taskctx, entity_t ent, bool pass, byte colors[4]; QuatCopy (renderer->colormod, base_color); QuatCopy (skin->colors, colors); - if (Ent_HasComponent (ent.id, ent.base + scene_colormap, ent.reg)) { - auto colormap = alias_get_colormap (ent); + auto colormap = Entity_GetColormap (ent); + if (colormap) { colors[0] = colormap->top * 16 + 8; colors[1] = colormap->bottom * 16 + 8; } diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index ae17908f8..16ee3c552 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -157,9 +157,6 @@ set_entity_model (int ent_ind, int modelindex) // the model type SET_ADD (&cl_forcelink, ent_ind); animation->nolerp = 1; // don't try to lerp when the model has changed - if (ent_ind <= cl.maxclients) { - renderer->skin = Skin_SetColormap (renderer->skin, ent_ind); - } } void @@ -236,21 +233,16 @@ CL_RelinkEntities (void) if (SET_TEST_MEMBER (&cl_forcelink, i) || new->colormap != old->colormap) { old->colormap = new->colormap; - renderer->skin = Skin_SetColormap (renderer->skin, new->colormap); } if (SET_TEST_MEMBER (&cl_forcelink, i) || new->skinnum != old->skinnum) { old->skinnum = new->skinnum; renderer->skinnum = new->skinnum; if (i <= cl.maxclients) { - colormap_t colormap = { + Entity_SetColormap (ent, &(colormap_t) { .top = cl.players[i - 1].topcolor, .bottom = cl.players[i - 1].bottomcolor, - }; - Ent_SetComponent (ent.id, ent.base + scene_colormap, ent.reg, &colormap); - renderer->skin = Skin_SetColormap (renderer->skin, i); - Skin_SetTranslation (i, cl.players[i - 1].topcolor, - cl.players[i - 1].bottomcolor); + }); } } diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index 738dc73a2..ac0c38029 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -931,17 +931,11 @@ CL_ParseServerMessage (void) Host_Error ("CL_ParseServerMessage: svc_updatecolors > " "MAX_SCOREBOARD"); } else { - entity_t ent = CL_GetEntity (i + 1); - renderer_t *renderer = Ent_GetComponent (ent.id, ent.base + scene_renderer, ent.reg); byte col = MSG_ReadByte (net_message); byte top = col >> 4; byte bot = col & 0xf; - if (top != cl.players[i].topcolor - || bot != cl.players[i].bottomcolor) - Skin_SetTranslation (i + 1, top, bot); cl.players[i].topcolor = top; cl.players[i].bottomcolor = bot; - renderer->skin = Skin_SetColormap (renderer->skin, i + 1); Sbar_UpdateInfo (i); } break; diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 1626f99a7..28df77bc2 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -217,18 +217,14 @@ CL_LinkPacketEntities (void) && cl.players[new->colormap - 1].name->value[0] && new->modelindex == cl_playerindex) { player_info_t *player = &cl.players[new->colormap - 1]; - colormap_t colormap = { + Entity_SetColormap (ent, &(colormap_t) { .top = player->topcolor, .bottom = player->bottomcolor, - }; - Ent_SetComponent (ent.id, ent.base + scene_colormap, ent.reg, &colormap); - renderer->skin = Skin_SetSkin (renderer->skin, new->colormap, - player->skinname->value); - renderer->skin = Skin_SetColormap (renderer->skin, - new->colormap); + }); + renderer->skin = Skin_SetSkin (player->skinname->value, + new->colormap); } else { - renderer->skin = Skin_SetColormap (renderer->skin, 0); - Ent_RemoveComponent (ent.id, ent.base + scene_colormap, ent.reg); + Entity_RemoveColormap (ent); } } @@ -489,11 +485,10 @@ CL_LinkPlayers (void) renderer->onlyshadows = (cl_player_shadows && j == cl.playernum && !chase_active); - colormap_t colormap = { + Entity_SetColormap (ent, &(colormap_t) { .top = player->topcolor, .bottom = player->bottomcolor, - }; - Ent_SetComponent (ent.id, ent.base + scene_colormap, ent.reg, &colormap); + }); // predict only half the move to minimize overruns msec = 500 * (playertime - state->state_time); diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index c96a7acf0..710f46b72 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -1021,11 +1021,7 @@ CL_ProcessUserInfo (int slot, player_info_t *player) const char *spec = Info_ValueForKey (player->userinfo, "*spectator"); player->spectator = spec && *spec; - Skin_SetTranslation (slot + 1, player->topcolor, - player->bottomcolor); - player->skin = Skin_SetSkin (player->skin, slot + 1, - player->skinname->value); - player->skin = Skin_SetColormap (player->skin, slot + 1); + player->skin = Skin_SetSkin (player->skinname->value, slot + 1); Sbar_UpdateInfo (slot); }