From fae52291efa344ad98f83a13308ffa5dd583a11e Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 7 Dec 2009 15:27:09 +0000 Subject: [PATCH] mdl skin loading is now more memory-efficient (now stores the original pixels and uploads textures on demand - many skins are never used, so this saves some system memory) added palette_featureflags[] for use by mdl skin loading added TEXF_PRECACHE to all texture uploads that did not use it added skinframe->hasalpha flag to clean up code removed R_TextureHasAlpha function r_glsl 1 no longer uploads fog textures r_glsl 0, gl_combine 0 no longer loads gloss/normalmaps git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9550 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_gecko.c | 2 +- clvm_cmds.c | 2 +- gl_draw.c | 2 +- gl_rmain.c | 187 +++++++++++++++++++++++++++++++------------------ gl_textures.c | 5 -- model_alias.c | 6 +- model_brush.c | 6 +- model_shared.c | 5 +- model_shared.h | 13 +++- model_sprite.c | 2 +- palette.c | 14 ++++ palette.h | 9 +++ r_shadow.c | 12 ++-- r_textures.h | 1 - render.h | 1 - 15 files changed, 170 insertions(+), 97 deletions(-) diff --git a/cl_gecko.c b/cl_gecko.c index d17bf964..72764efe 100644 --- a/cl_gecko.c +++ b/cl_gecko.c @@ -449,7 +449,7 @@ static void cl_gecko_updatecallback( rtexture_t *texture, void* callbackData ) { static void cl_gecko_linktexture( clgecko_t *instance ) { // TODO: assert that instance->texture == NULL instance->texture = R_LoadTexture2D( cl_geckotexturepool, instance->name, - instance->texWidth, instance->texHeight, NULL, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PERSISTENT, NULL ); + instance->texWidth, instance->texHeight, NULL, TEXTYPE_BGRA, TEXF_ALWAYSPRECACHE | TEXF_ALPHA | TEXF_PERSISTENT, NULL ); R_MakeTextureDynamic( instance->texture, cl_gecko_updatecallback, instance ); CL_LinkDynTexture( instance->name, instance->texture ); } diff --git a/clvm_cmds.c b/clvm_cmds.c index 756da39a..af074998 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -3174,7 +3174,7 @@ void VM_CL_R_PolygonBegin (void) sf = NULL; if(*picname) { - tf = TEXF_ALPHA; + tf = TEXF_PRECACHE | TEXF_ALPHA; if((int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MIPMAP) tf |= TEXF_MIPMAP; diff --git a/gl_draw.c b/gl_draw.c index 820d6c54..7a0fa727 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -502,7 +502,7 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, u pic->height = height; if (pic->tex) R_FreeTexture(pic->tex); - pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, alpha ? TEXF_ALPHA : 0, NULL); + pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, TEXF_PRECACHE | (alpha ? TEXF_ALPHA : 0), NULL); return pic; } diff --git a/gl_rmain.c b/gl_rmain.c index 0a30545f..c017e252 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -30,6 +30,10 @@ rtexturepool_t *r_main_texturepool; static int r_frame = 0; ///< used only by R_GetCurrentTexture +qboolean r_loadnormalmap; +qboolean r_loadgloss; +qboolean r_loadfog; + // // screen size info // @@ -322,7 +326,7 @@ static void R_BuildNoTexture(void) } } } - r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, NULL); + r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_MIPMAP | TEXF_PERSISTENT, NULL); } static void R_BuildWhiteCube(void) @@ -2512,15 +2516,8 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \ } -skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int textureflags, qboolean complain, qboolean *has_alpha) +skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain) { - // FIXME: it should be possible to disable loading various layers using - // cvars, to prevent wasted loading time and memory usage if the user does - // not want them - qboolean loadnormalmap = true; - qboolean loadgloss = true; - qboolean loadpantsandshirt = true; - qboolean loadglow = true; int j; unsigned char *pixels; unsigned char *bumppixels; @@ -2529,9 +2526,6 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl int basepixels_height; skinframe_t *skinframe; - if (has_alpha) - *has_alpha = false; - if (cls.state == ca_dedicated) return NULL; @@ -2561,6 +2555,7 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; + skinframe->hasalpha = false; basepixels_width = image_width; basepixels_height = image_height; @@ -2569,13 +2564,16 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl if (textureflags & TEXF_ALPHA) { for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4) + { if (basepixels[j] < 255) + { + skinframe->hasalpha = true; break; - if (j < basepixels_width * basepixels_height * 4) + } + } + if (r_loadfog && skinframe->hasalpha) { // has transparent pixels - if (has_alpha) - *has_alpha = true; pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); for (j = 0;j < image_width * image_height * 4;j += 4) { @@ -2593,7 +2591,7 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); // _norm is the name used by tenebrae and has been adopted as standard - if (loadnormalmap) + if (r_loadnormalmap) { if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL) { @@ -2620,10 +2618,10 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl // _luma is supported for tenebrae compatibility // (I think it's a very stupid name, but oh well) // _glow is the preferred name - if (loadglow && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false)) != NULL || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false)) != NULL)) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;} - if (loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false)) != NULL) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;} - if (loadpantsandshirt && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false)) != NULL) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;} - if (loadpantsandshirt && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false)) != NULL) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;} + if ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false))) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;} + if (r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false))) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;} + if ((pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false))) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;} + if ((pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false))) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;} if (basepixels) Mem_Free(basepixels); @@ -2631,25 +2629,6 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl return skinframe; } -skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain) -{ - return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, NULL); -} - -static rtexture_t *R_SkinFrame_TextureForSkinLayer(const unsigned char *in, int width, int height, const char *name, const unsigned int *palette, int textureflags, qboolean force) -{ - int i; - if (!force) - { - for (i = 0;i < width*height;i++) - if (((unsigned char *)&palette[in[i]])[3] > 0) - break; - if (i == width*height) - return NULL; - } - return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette); -} - // this is only used by .spr32 sprites, HL .spr files, HL .bsp files skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height) { @@ -2674,6 +2653,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; + skinframe->hasalpha = false; // if no data was provided, then clearly the caller wanted to get a blank skinframe if (!skindata) @@ -2682,7 +2662,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co if (developer_loading.integer) Con_Printf("loading 32bit skin \"%s\"\n", name); - if (r_shadow_bumpscale_basetexture.value > 0) + if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0) { temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8); temp2 = temp1 + width * height * 4; @@ -2694,9 +2674,14 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co if (textureflags & TEXF_ALPHA) { for (i = 3;i < width * height * 4;i += 4) + { if (skindata[i] < 255) + { + skinframe->hasalpha = true; break; - if (i < width * height * 4) + } + } + if (r_loadfog && skinframe->hasalpha) { unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4); memcpy(fogpixels, skindata, width * height * 4); @@ -2716,8 +2701,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height) { int i; - unsigned char *temp1, *temp2; - unsigned int *palette; + int featuresmask; skinframe_t *skinframe; if (cls.state == ca_dedicated) @@ -2728,8 +2712,6 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i if (skinframe && skinframe->base) return skinframe; - palette = (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete)); - skinframe->stain = NULL; skinframe->merged = NULL; skinframe->base = r_texture_notexture; @@ -2739,6 +2721,7 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; + skinframe->hasalpha = false; // if no data was provided, then clearly the caller wanted to get a blank skinframe if (!skindata) @@ -2747,8 +2730,60 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i if (developer_loading.integer) Con_Printf("loading quake skin \"%s\"\n", name); - if (r_shadow_bumpscale_basetexture.value > 0) + // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped) + skinframe->qpixels = Mem_Alloc(r_main_mempool, width*height); + memcpy(skinframe->qpixels, skindata, width*height); + skinframe->qwidth = width; + skinframe->qheight = height; + + featuresmask = 0; + for (i = 0;i < width * height;i++) + featuresmask |= palette_featureflags[skindata[i]]; + + skinframe->hasalpha = false; + skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT)); + skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0; + skinframe->qgeneratemerged = true; + skinframe->qgeneratebase = skinframe->qhascolormapping; + skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW); + + R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + + return skinframe; +} + +static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped) +{ + int width; + int height; + unsigned char *skindata; + + if (!skinframe->qpixels) + return; + + if (!skinframe->qhascolormapping) + colormapped = false; + + if (colormapped) + { + if (!skinframe->qgeneratebase) + return; + } + else { + if (!skinframe->qgeneratemerged) + return; + } + + width = skinframe->qwidth; + height = skinframe->qheight; + skindata = skinframe->qpixels; + + if (skinframe->qgeneratenmap) + { + unsigned char *temp1, *temp2; + skinframe->qgeneratenmap = false; temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8); temp2 = temp1 + width * height * 4; // use either a custom palette or the quake palette @@ -2757,30 +2792,31 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, skinframe->textureflags | TEXF_ALPHA, NULL); Mem_Free(temp1); } - // use either a custom palette, or the quake palette - skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette, skinframe->textureflags, true); // all - if (loadglowtexture) - skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_bgra_onlyfullbrights, skinframe->textureflags, false); // glow - if (loadpantsandshirt) + + if (skinframe->qgenerateglow) { - skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_bgra_pantsaswhite, skinframe->textureflags, false); // pants - skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_bgra_shirtaswhite, skinframe->textureflags, false); // shirt + skinframe->qgenerateglow = false; + skinframe->glow = R_LoadTexture2D(r_main_texturepool, va("%s_glow", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, palette_bgra_onlyfullbrights); // glow } - if (skinframe->pants || skinframe->shirt) - skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename), loadglowtexture ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap, skinframe->textureflags, false); // no special colors - if (textureflags & TEXF_ALPHA) + + if (colormapped) { - for (i = 0;i < width * height;i++) - if (((unsigned char *)palette_bgra_alpha)[skindata[i]*4+3] < 255) - break; - if (i < width * height) - skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), palette_bgra_alpha, skinframe->textureflags, true); // fog mask + skinframe->qgeneratebase = false; + skinframe->base = R_LoadTexture2D(r_main_texturepool, va("%s_nospecial", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap); + skinframe->pants = R_LoadTexture2D(r_main_texturepool, va("%s_pants", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, palette_bgra_pantsaswhite); + skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va("%s_shirt", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, palette_bgra_shirtaswhite); + } + else + { + skinframe->qgeneratemerged = false; + skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete); } - R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]); - //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); - - return skinframe; + if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase) + { + Mem_Free(skinframe->qpixels); + skinframe->qpixels = NULL; + } } skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette) @@ -2805,6 +2841,7 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; + skinframe->hasalpha = false; // if no data was provided, then clearly the caller wanted to get a blank skinframe if (!skindata) @@ -2813,14 +2850,19 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co if (developer_loading.integer) Con_Printf("loading embedded 8bit image \"%s\"\n", name); - skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, skinframe->basename, palette, skinframe->textureflags, true); + skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, palette); if (textureflags & TEXF_ALPHA) { for (i = 0;i < width * height;i++) - if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255) + { + if (((unsigned char *)palette)[skindata[i]*4+3] < 255) + { + skinframe->hasalpha = true; break; - if (i < width * height) - skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask + } + } + if (r_loadfog && skinframe->hasalpha) + skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, alphapalette); } R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]); @@ -2846,6 +2888,7 @@ skinframe_t *R_SkinFrame_LoadMissing(void) skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; + skinframe->hasalpha = false; skinframe->avgcolor[0] = rand() / RAND_MAX; skinframe->avgcolor[1] = rand() / RAND_MAX; @@ -2908,6 +2951,10 @@ void R_Main_ResizeViewCache(void) void gl_main_start(void) { + r_loadnormalmap = r_glsl.integer || gl_combine.integer; + r_loadgloss = r_glsl.integer || gl_combine.integer; + r_loadfog = !r_glsl.integer; + r_numqueries = 0; r_maxqueries = 0; memset(r_queries, 0, sizeof(r_queries)); @@ -5817,6 +5864,8 @@ texture_t *R_GetCurrentTexture(texture_t *t) R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags); t->colormapping = VectorLength2(rsurface.colormap_pantscolor) + VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f); + if (t->currentskinframe->qpixels) + R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping); t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base; t->glosstexture = r_texture_black; t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white; diff --git a/gl_textures.c b/gl_textures.c index 94d04616..4b4f6cc3 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -1142,11 +1142,6 @@ rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL); } -int R_TextureHasAlpha(rtexture_t *rt) -{ - return rt ? (((gltexture_t *)rt)->flags & TEXF_ALPHA) != 0 : false; -} - int R_TextureWidth(rtexture_t *rt) { return rt ? ((gltexture_t *)rt)->inputwidth : 0; diff --git a/model_alias.c b/model_alias.c index e8feab96..7781eb0f 100644 --- a/model_alias.c +++ b/model_alias.c @@ -897,7 +897,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski //texture->textureflags = 0; texture->basematerialflags = MATERIALFLAG_WALL; - if (texture->currentskinframe->fog) + if (texture->currentskinframe->hasalpha) texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; texture->currentmaterialflags = texture->basematerialflags; } @@ -1220,8 +1220,8 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j); else dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i); - if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS)) - Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight)); + if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS | TEXF_PRECACHE)) + Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight)); datapointer += skinwidth * skinheight; totalskins++; } diff --git a/model_brush.c b/model_brush.c index 528c59fa..c9c41cfc 100644 --- a/model_brush.c +++ b/model_brush.c @@ -1601,7 +1601,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) Mem_Free(freepixels); } else if (mtdata) // texture included - skinframe = R_SkinFrame_LoadInternalQuake(tx->name, TEXF_ALPHA | TEXF_MIPMAP | TEXF_PRECACHE | (r_picmipworld.integer ? TEXF_PICMIP : 0), false, r_fullbrights.integer, mtdata, tx->width, tx->height); + skinframe = R_SkinFrame_LoadInternalQuake(tx->name, TEXF_PRECACHE | TEXF_MIPMAP | (r_picmipworld.integer ? TEXF_PICMIP : 0), false, r_fullbrights.integer, mtdata, tx->width, tx->height); } // if skinframe is still NULL the "missing" texture will be used if (skinframe) @@ -1625,7 +1625,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW; else tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW | MATERIALFLAG_WATERALPHA | MATERIALFLAG_WATERSHADER; - if (tx->skinframes[0] && tx->skinframes[0]->fog) + if (tx->skinframes[0] && tx->skinframes[0]->hasalpha) tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; } else if (!strncmp(tx->name, "mirror", 6)) // Tenebrae @@ -1638,7 +1638,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) tx->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW; else if (!strcmp(tx->name, "caulk")) tx->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; - else if (tx->skinframes[0] && tx->skinframes[0]->fog) + else if (tx->skinframes[0] && tx->skinframes[0]->hasalpha) tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // start out with no animation diff --git a/model_shared.c b/model_shared.c index faec4c5a..6a0d502b 100644 --- a/model_shared.c +++ b/model_shared.c @@ -2238,10 +2238,9 @@ nothing GL_ZERO GL_ONE { if (fallback) { - qboolean has_alpha; - if ((texture->skinframes[0] = R_SkinFrame_LoadExternal_CheckAlpha(texture->name, defaulttexflags, false, &has_alpha))) + if ((texture->skinframes[0] = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false))) { - if(has_alpha && (defaulttexflags & TEXF_ALPHA)) + if(texture->skinframes[0]->hasalpha) texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; } else diff --git a/model_shared.h b/model_shared.h index 3d14ec91..b73a2355 100644 --- a/model_shared.h +++ b/model_shared.h @@ -68,10 +68,19 @@ typedef struct skinframe_s // on each level change for the used skinframes, if some are not used they // are freed int loadsequence; - // on 32bit systems this makes the struct 128 bytes long - int padding; + // indicates whether this texture has transparent pixels + qboolean hasalpha; // average texture color, if applicable float avgcolor[4]; + // for mdl skins, we actually only upload on first use (many are never used, and they are almost never used in both base+pants+shirt and merged modes) + unsigned char *qpixels; + int qwidth; + int qheight; + qboolean qhascolormapping; + qboolean qgeneratebase; + qboolean qgeneratemerged; + qboolean qgeneratenmap; + qboolean qgenerateglow; } skinframe_t; diff --git a/model_sprite.c b/model_sprite.c index d944da3f..a08cb8c3 100644 --- a/model_sprite.c +++ b/model_sprite.c @@ -52,7 +52,7 @@ static void Mod_SpriteSetupTexture(texture_t *texture, skinframe_t *skinframe, q texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT; if (additive) texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; - else if (skinframe->fog) + else if (skinframe->hasalpha) texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; texture->currentmaterialflags = texture->basematerialflags; texture->numskinframes = 1; diff --git a/palette.c b/palette.c index 24ee2d00..e397f155 100644 --- a/palette.c +++ b/palette.c @@ -20,6 +20,7 @@ unsigned int palette_bgra_pantsaswhite[256]; unsigned int palette_bgra_shirtaswhite[256]; unsigned int palette_bgra_transparent[256]; unsigned int palette_bgra_embeddedpic[256]; +unsigned char palette_featureflags[256]; // John Carmack said the quake palette.lmp can be considered public domain because it is not an important asset to id, so I include it here as a fallback if no external palette file is found. unsigned char host_quakepal[768] = @@ -108,6 +109,19 @@ void Palette_SetupSpecialPalettes(void) reversed_end = 224; transparentcolor = 255; + for (i = 0;i < 256;i++) + palette_featureflags[i] = PALETTEFEATURE_STANDARD; + for (i = reversed_start;i < reversed_end;i++) + palette_featureflags[i] = PALETTEFEATURE_REVERSED; + for (i = pants_start;i < pants_end;i++) + palette_featureflags[i] = PALETTEFEATURE_PANTS; + for (i = shirt_start;i < shirt_end;i++) + palette_featureflags[i] = PALETTEFEATURE_SHIRT; + for (i = fullbright_start;i < fullbright_end;i++) + palette_featureflags[i] = PALETTEFEATURE_GLOW; + palette_featureflags[0] = PALETTEFEATURE_ZERO; + palette_featureflags[transparentcolor] = PALETTEFEATURE_TRANSPARENT; + for (i = 0;i < 256;i++) palette_bgra_transparent[i] = palette_bgra_complete[i]; palette_bgra_transparent[transparentcolor] = 0; diff --git a/palette.h b/palette.h index e534b9c5..f9044653 100644 --- a/palette.h +++ b/palette.h @@ -2,6 +2,14 @@ #ifndef PALLETE_H #define PALLETE_H +#define PALETTEFEATURE_STANDARD 1 +#define PALETTEFEATURE_REVERSED 2 +#define PALETTEFEATURE_PANTS 4 +#define PALETTEFEATURE_SHIRT 8 +#define PALETTEFEATURE_GLOW 16 +#define PALETTEFEATURE_ZERO 32 +#define PALETTEFEATURE_TRANSPARENT 128 + extern unsigned char palette_rgb[256][3]; extern unsigned char palette_rgb_pantscolormap[16][3]; extern unsigned char palette_rgb_shirtcolormap[16][3]; @@ -19,6 +27,7 @@ extern unsigned int palette_bgra_pantsaswhite[256]; extern unsigned int palette_bgra_shirtaswhite[256]; extern unsigned int palette_bgra_transparent[256]; extern unsigned int palette_bgra_embeddedpic[256]; +extern unsigned char palette_featureflags[256]; // used by hardware gamma functions in vid_* files void BuildGammaTable8(float prescale, float gamma, float scale, float base, float contrastboost, unsigned char *out, int rampsize); diff --git a/r_shadow.c b/r_shadow.c index d9a4933e..4413c062 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -1737,7 +1737,7 @@ static void R_Shadow_MakeTextures(void) R_Shadow_MakeTextures_MakeCorona(); // Editor light sprites - r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) "................" ".3............3." "..5...2332...5.." @@ -1755,7 +1755,7 @@ static void R_Shadow_MakeTextures(void) ".3............3." "................" , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); - r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) "................" "................" "......1111......" @@ -1773,7 +1773,7 @@ static void R_Shadow_MakeTextures(void) "................" "................" , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); - r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) "................" "................" "......1111......" @@ -1791,7 +1791,7 @@ static void R_Shadow_MakeTextures(void) "................" "................" , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); - r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) "................" "................" "......2772......" @@ -1809,7 +1809,7 @@ static void R_Shadow_MakeTextures(void) "................" "................" , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); - r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) "................" "................" "......2772......" @@ -1827,7 +1827,7 @@ static void R_Shadow_MakeTextures(void) "................" "................" , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); - r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *) + r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (unsigned char *) "................" ".777752..257777." ".742........247." diff --git a/r_textures.h b/r_textures.h index e5ba7306..0ef3ab2c 100644 --- a/r_textures.h +++ b/r_textures.h @@ -99,7 +99,6 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in int R_RealGetTexture (rtexture_t *rt); // returns true if the texture is transparent (useful for rendering code) -int R_TextureHasAlpha(rtexture_t *rt); // returns width of texture, as was specified when it was uploaded int R_TextureWidth(rtexture_t *rt); diff --git a/render.h b/render.h index 969e130a..f5a77f8b 100644 --- a/render.h +++ b/render.h @@ -140,7 +140,6 @@ void R_SkinFrame_Purge(void); skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ); skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add); skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain); -skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int textureflags, qboolean complain, qboolean *has_alpha); skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height); skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height); skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette); -- 2.39.2