From 346ed29f4954383fba34ad429645fc023a2274da Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 15 Jan 2024 10:28:02 +0900 Subject: [PATCH] [skin] Implement top/bottom colors for gl They don't work yet if the entity does not have an external skin. --- include/mod_internal.h | 7 +- libs/models/gl_skin.c | 95 +++++++++++++++++++++------ libs/video/renderer/gl/gl_mod_alias.c | 21 +++--- 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/include/mod_internal.h b/include/mod_internal.h index a9ec0edb2..b703ee141 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -122,9 +122,13 @@ tex_t *Skin_DupTex (const tex_t *tex); typedef struct skin_s { tex_t *tex; uint32_t id; - uint32_t fb; } skin_t; +typedef struct glskin_s { + uint32_t id; + uint32_t fb; +} glskin_t; + skin_t *Skin_Get (uint32_t skin) __attribute__((pure)); void sw_Skin_SetupSkin (skin_t *skin, int cmap); @@ -137,5 +141,6 @@ uint32_t glsl_Skin_Colormap (const colormap_t *colormap); void gl_Skin_SetupSkin (skin_t *skin, int cmap); void gl_Skin_Destroy (skin_t *skin); +glskin_t gl_Skin_Get (const skin_t *skin, const colormap_t *colormap); #endif// __mod_internal_h diff --git a/libs/models/gl_skin.c b/libs/models/gl_skin.c index 90bd2b9a3..3b9bbad4e 100644 --- a/libs/models/gl_skin.c +++ b/libs/models/gl_skin.c @@ -41,6 +41,7 @@ #include #include "QF/cvar.h" +#include "QF/fbsearch.h" #include "QF/image.h" #include "QF/model.h" #include "QF/skin.h" @@ -54,11 +55,18 @@ #include "mod_internal.h" #include "r_internal.h" -// FIXME colormap (top/bottom colors) -//static byte skin_cmap[MAX_TRANSLATIONS][256]; +typedef struct { + const tex_t *tex; + glskin_t skin; +} skinpair_t; + +#define MAX_GLSKINS 64 + +static skinpair_t skin_table[256][MAX_GLSKINS]; +static int skin_counts[256]; static void -build_skin_8 (tex_t *tex, int texnum, byte *translate, +build_skin_8 (const tex_t *tex, int texnum, byte *translate, unsigned scaled_width, unsigned scaled_height, bool alpha) { // Improvements should be mirrored in GL_ResampleTexture in gl_textures.c @@ -84,7 +92,7 @@ build_skin_8 (tex_t *tex, int texnum, byte *translate, } static void -build_skin_32 (tex_t *tex, int texnum, byte *translate, +build_skin_32 (const tex_t *tex, int texnum, byte *translate, unsigned scaled_width, unsigned scaled_height, bool alpha) { // Improvements should be mirrored in GL_ResampleTexture in gl_textures.c @@ -124,12 +132,40 @@ build_skin_32 (tex_t *tex, int texnum, byte *translate, gl_aniso); } -void -gl_Skin_SetupSkin (skin_t *skin, int cmap) +static int +skinpair_cmp (const void *_tex, const void *_skinpair) { - //skin->tex = Skin_DupTex (skin->tex); - tex_t *tex = skin->tex; - skin->tex = nullptr; // tex memory is only temporarily allocated + const tex_t *tex = _tex; + const skinpair_t *skinpair = _skinpair; + intptr_t diff = (intptr_t) tex - (intptr_t) skinpair->tex; + return diff < 0 ? -1 : diff > 0 ? 1 : 0; +} + +glskin_t +gl_Skin_Get (const skin_t *skin, const colormap_t *colormap) +{ + if (!skin || !colormap) { + return (glskin_t) {}; + } + + byte top = colormap->top & 0x0f; + byte bot = colormap->bottom & 0x0f; + int ind = top | (bot << 4); + skinpair_t *sp = fbsearch (skin->tex, skin_table[ind], skin_counts[ind], + sizeof (skinpair_t), skinpair_cmp); + if (sp && sp->tex == skin->tex) { + return sp->skin; + } + if (skin_counts[ind] == MAX_GLSKINS) { + return (glskin_t) {}; + } + sp = sp ? sp + 1 : skin_table[ind]; + int insert = sp - skin_table[ind]; + memmove (&skin_table[ind][insert + 1], &skin_table[ind][insert], + sizeof (skinpair_t[skin_counts[ind] - insert])); + skin_counts[ind]++; + + sp->tex = skin->tex; auto build_skin = vid.is8bit ? build_skin_8 : build_skin_32; @@ -141,24 +177,43 @@ gl_Skin_SetupSkin (skin_t *skin, int cmap) swidth = max (swidth, 1); sheight = max (sheight, 1); - int size = tex->width * tex->height; + byte palette[256]; + Skin_SetPalette (palette, top, bot); + qfglGenTextures (1, &sp->skin.id); + build_skin_32 (sp->tex, sp->skin.id, palette, swidth, sheight, false); + + int size = sp->tex->width * sp->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; + if (Mod_CalcFullbright (fbskin, skin->tex->data, size)) { + tex_t fb_tex = *sp->tex; fb_tex.data = fbskin; - qfglGenTextures (1, &skin->fb); - build_skin (&fb_tex, skin->fb, vid.colormap8, swidth, sheight, true); + qfglGenTextures (1, &sp->skin.fb); + build_skin (&fb_tex, sp->skin.fb, palette, swidth, sheight, true); } + return sp->skin; +} + +void +gl_Skin_SetupSkin (skin_t *skin, int cmap) +{ + skin->tex = Skin_DupTex (skin->tex); } void gl_Skin_Destroy (skin_t *skin) { - qfglDeleteTextures (1, &skin->id); - if (skin->fb) { - qfglDeleteTextures (1, &skin->fb); + for (int i = 0; i < 256; i++) { + for (int j = skin_counts[i]; j-- > 0; ) { + auto sp = &skin_table[i][j]; + if (sp->tex == skin->tex) { + qfglDeleteTextures (1, &sp->skin.id); + if (sp->skin.fb) { + qfglDeleteTextures (1, &sp->skin.fb); + } + skin_counts[i]--; + memmove (&skin_table[i][j], &skin_table[i][j + 1], + sizeof (skinpair_t[skin_counts[i] - j])); + } + } } } diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index 2b5aa3964..da6b5d3c4 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -558,14 +558,14 @@ 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 && !gl_nocolors) { - skin_t *skin = Skin_Get (renderer->skin); + if (!gl_nocolors) { + skin_t *skin = renderer->skin ? Skin_Get (renderer->skin) : nullptr; + auto colormap = Entity_GetColormap (e); + auto glskin = gl_Skin_Get (skin, colormap); - if (skin) { - texture = skin->id; - if (gl_fb_models) { - fb_texture = skin->fb; - } + if (glskin.id) { + texture = glskin.id; + fb_texture = glskin.fb; } } if (!texture) { @@ -574,9 +574,10 @@ gl_R_DrawAliasModel (entity_t e) e.reg); skindesc = R_AliasGetSkindesc (animation, renderer->skinnum, paliashdr); texture = skindesc->texnum; - if (gl_fb_models && !is_fullbright) { - fb_texture = skindesc->fb_texnum; - } + fb_texture = skindesc->fb_texnum; + } + if (!gl_fb_models || is_fullbright) { + fb_texture = 0; } if (paliashdr->mdl.ident == HEADER_MDL16) {