From 0766a43538f3b526cba347157d5259bb3e5785a9 Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 11 Apr 2018 05:28:24 +0000 Subject: [PATCH] Added Draw_GetPicWidth, Draw_GetPicHeight, Draw_IsPicLoaded functions and moved cachepic_t to live in gl_draw.c (no longer visible to other modules). Changed Draw_CachePic to use the R_SkinFrame_LoadExternal system, and reworked font loading to use Draw_CachePic rather than keeping track of textures itself. R_SkinFrame_LoadExternal can now load gfx.wad lumps and gfx/*.lmp files, and the embedded images have been moved to image.c as they are now returned as raw images, suitable for R_SkinFrame_LoadExternal to use. Reworked cl_video code to not need the cl_dyntexture system (which has been removed); it still uses dynamic texture callbacks (which is a feature of rtexture_t). Changed the parameters to Mod_LoadCustomMaterial and a few other model_shared.c functions to not assume loadmodel is the owner of memory and textures; this was necessary for Draw_CachePic to be able to use R_SkinFrame_LoadExternal. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12385 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_dyntexture.c | 93 ----- cl_dyntexture.h | 20 - cl_particles.c | 9 +- cl_screen.c | 32 +- cl_video.c | 43 +-- cl_video.h | 11 +- clvm_cmds.c | 10 +- console.c | 6 +- darkplaces-dedicated-vs2017.vcxproj | 2 - darkplaces-sdl2-vs2017.vcxproj | 2 - darkplaces-wgl-vs2017.vcxproj | 2 - draw.h | 40 +- ft2.c | 20 +- gl_draw.c | 569 ++++++---------------------- gl_rmain.c | 96 ++++- gl_rsurf.c | 2 +- gl_textures.c | 2 +- image.c | 469 ++++++++++++++++++++++- image.h | 4 + libcurl.c | 2 +- menu.c | 48 +-- model_alias.c | 62 +-- model_brush.c | 12 +- model_shared.c | 176 +++++---- model_shared.h | 14 +- model_sprite.c | 6 +- prvm_cmds.c | 9 +- r_lightning.c | 6 +- render.h | 5 +- sbar.c | 16 +- wad.c | 8 +- wad.h | 2 +- 32 files changed, 917 insertions(+), 881 deletions(-) diff --git a/cl_dyntexture.c b/cl_dyntexture.c index fb378def..e69de29b 100644 --- a/cl_dyntexture.c +++ b/cl_dyntexture.c @@ -1,93 +0,0 @@ -// Andreas Kirsch 07 - -#include "quakedef.h" -#include "cl_dyntexture.h" - -typedef struct dyntexture_s { - // everything after DYNAMIC_TEXTURE_PATH_PREFIX - char name[ MAX_QPATH + 32 ]; - // texture pointer (points to r_texture_white at first) - rtexture_t *texture; -} dyntexture_t; - -static dyntexture_t dyntextures[ MAX_DYNAMIC_TEXTURE_COUNT ]; -static unsigned dyntexturecount; - -#define DEFAULT_DYNTEXTURE r_texture_grey128 - -static dyntexture_t * cl_finddyntexture( const char *name, qboolean warnonfailure ) { - unsigned i; - dyntexture_t *dyntexture = NULL; - - // sanity checks - make sure its actually a dynamic texture path - if( !name || !*name || strncmp( name, CLDYNTEXTUREPREFIX, sizeof( CLDYNTEXTUREPREFIX ) - 1 ) != 0 ) { - // TODO: print a warning or something - if (warnonfailure) - Con_Printf( "cl_finddyntexture: Bad dynamic texture name '%s'\n", name ); - return NULL; - } - - for( i = 0 ; i < dyntexturecount ; i++ ) { - dyntexture = &dyntextures[ i ]; - if( dyntexture->name && strcmp( dyntexture->name, name ) == 0 ) { - return dyntexture; - } - } - - if( dyntexturecount == MAX_DYNAMIC_TEXTURE_COUNT ) { - // TODO: warn or expand the array, etc. - return NULL; - } - dyntexture = &dyntextures[ dyntexturecount++ ]; - strlcpy( dyntexture->name, name, sizeof( dyntexture->name ) ); - dyntexture->texture = DEFAULT_DYNTEXTURE; - return dyntexture; -} - -rtexture_t * CL_GetDynTexture( const char *name ) { - dyntexture_t *dyntexture = cl_finddyntexture( name, false ); - if( dyntexture ) { - return dyntexture->texture; - } else { - return NULL; - } -} - -void CL_LinkDynTexture( const char *name, rtexture_t *texture ) { - dyntexture_t *dyntexture; - cachepic_t *cachepic; - skinframe_t *skinframe; - - dyntexture = cl_finddyntexture( name, true ); - if( !dyntexture ) { - Con_Printf( "CL_LinkDynTexture: internal error in cl_finddyntexture!\n" ); - return; - } - // TODO: assert dyntexture != NULL! - if( dyntexture->texture != texture ) { - dyntexture->texture = texture; - - cachepic = Draw_CachePic_Flags( name, CACHEPICFLAG_NOTPERSISTENT ); - // TODO: assert cachepic and skinframe should be valid pointers... - // TODO: assert cachepic->tex = dyntexture->texture - cachepic->tex = texture; - // update cachepic's size, too - cachepic->width = R_TextureWidth( texture ); - cachepic->height = R_TextureHeight( texture ); - - // update skinframes - skinframe = NULL; - while( (skinframe = R_SkinFrame_FindNextByName( skinframe, name )) != NULL ) { - skinframe->base = texture; - // simply reset the compare* attributes of skinframe - skinframe->comparecrc = 0; - skinframe->comparewidth = skinframe->compareheight = 0; - // this is kind of hacky - } - } -} - -void CL_UnlinkDynTexture( const char *name ) { - CL_LinkDynTexture( name, DEFAULT_DYNTEXTURE ); -} - diff --git a/cl_dyntexture.h b/cl_dyntexture.h index 130dc167..e69de29b 100644 --- a/cl_dyntexture.h +++ b/cl_dyntexture.h @@ -1,20 +0,0 @@ -// Andreas 'Black' Kirsch 07 -#ifndef CL_DYNTEXTURE_H -#define CL_DYNTEXTURE_H - -#define CLDYNTEXTUREPREFIX "_dynamic/" - -// always path fully specified names to the dynamic texture functions! (ie. with the _dynamic/ prefix, etc.!) - -// return a valid texture handle for a dynamic texture (might be filler texture if it hasnt been initialized yet) -// or NULL if its not a valid dynamic texture name -rtexture_t * CL_GetDynTexture( const char *name ); - -// link a texture handle as dynamic texture and update texture handles in the renderer and draw_* accordingly -void CL_LinkDynTexture( const char *name, rtexture_t *texture ); - -// unlink a texture handle from its name -void CL_UnlinkDynTexture( const char *name ); - -#endif - diff --git a/cl_particles.c b/cl_particles.c index 9d64080b..b159698c 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -2180,7 +2180,7 @@ static void R_InitParticleTexture (void) // we invert it again during the blendfunc to make it work... #ifndef DUMPPARTICLEFONT - decalskinframe = R_SkinFrame_LoadExternal("particles/particlefont.tga", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, false); + decalskinframe = R_SkinFrame_LoadExternal("particles/particlefont.tga", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, false, false); if (decalskinframe) { particlefonttexture = decalskinframe->base; @@ -2427,12 +2427,7 @@ static void R_InitParticleTexture (void) Con_Printf("particles/particlefont.txt: texnum %i outside valid range (0 to %i)\n", i, MAX_PARTICLETEXTURES); continue; } - sf = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true); // note: this loads as sRGB if sRGB is active! - if(!sf) - { - // R_SkinFrame_LoadExternal already complained - continue; - } + sf = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, true); // note: this loads as sRGB if sRGB is active! particletexture[i].texture = sf->base; particletexture[i].s1 = s1; particletexture[i].t1 = t1; diff --git a/cl_screen.c b/cl_screen.c index abde7491..ece99e96 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -457,7 +457,7 @@ static void SCR_DrawPause (void) return; pic = Draw_CachePic ("gfx/pause"); - DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, (vid_conheight.integer - pic->height)/2, pic, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic ((vid_conwidth.integer - Draw_GetPicWidth(pic))/2, (vid_conheight.integer - Draw_GetPicHeight(pic))/2, pic, 0, 0, 1, 1, 1, 1, 0); } /* @@ -479,26 +479,26 @@ static void SCR_DrawBrand (void) { case 1: // bottom left x = 0; - y = vid_conheight.integer - pic->height; + y = vid_conheight.integer - Draw_GetPicHeight(pic); break; case 2: // bottom centre - x = (vid_conwidth.integer - pic->width) / 2; - y = vid_conheight.integer - pic->height; + x = (vid_conwidth.integer - Draw_GetPicWidth(pic)) / 2; + y = vid_conheight.integer - Draw_GetPicHeight(pic); break; case 3: // bottom right - x = vid_conwidth.integer - pic->width; - y = vid_conheight.integer - pic->height; + x = vid_conwidth.integer - Draw_GetPicWidth(pic); + y = vid_conheight.integer - Draw_GetPicHeight(pic); break; case 4: // centre right - x = vid_conwidth.integer - pic->width; - y = (vid_conheight.integer - pic->height) / 2; + x = vid_conwidth.integer - Draw_GetPicWidth(pic); + y = (vid_conheight.integer - Draw_GetPicHeight(pic)) / 2; break; case 5: // top right - x = vid_conwidth.integer - pic->width; + x = vid_conwidth.integer - Draw_GetPicWidth(pic); y = 0; break; case 6: // top centre - x = (vid_conwidth.integer - pic->width) / 2; + x = (vid_conwidth.integer - Draw_GetPicWidth(pic)) / 2; y = 0; break; case 7: // top left @@ -507,7 +507,7 @@ static void SCR_DrawBrand (void) break; case 8: // centre left x = 0; - y = (vid_conheight.integer - pic->height) / 2; + y = (vid_conheight.integer - Draw_GetPicHeight(pic)) / 2; break; default: return; @@ -2070,9 +2070,9 @@ static void SCR_DrawTouchscreenOverlay(void) DrawQ_Fill(a->rect[0] + 1, a->rect[1] + a->rect[3] - 2, a->rect[2] - 2, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); DrawQ_Fill(a->rect[0] + 2, a->rect[1] + a->rect[3] - 1, a->rect[2] - 4, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); } - pic = a->pic ? Draw_CachePic(a->pic) : NULL; - if (pic && pic->tex != r_texture_notexture) - DrawQ_Pic(a->rect[0], a->rect[1], Draw_CachePic(a->pic), a->rect[2], a->rect[3], 1, 1, 1, vid_touchscreen_overlayalpha.value * (0.5f + 0.5f * a->active), 0); + pic = a->pic ? Draw_CachePic_Flags(a->pic, CACHEPICFLAG_FAILONMISSING) : NULL; + if (Draw_IsPicLoaded(pic)) + DrawQ_Pic(a->rect[0], a->rect[1], pic, a->rect[2], a->rect[3], 1, 1, 1, vid_touchscreen_overlayalpha.value * (0.5f + 0.5f * a->active), 0); if (a->text && a->text[0]) { int textwidth = DrawQ_TextWidth(a->text, 0, a->textheight, a->textheight, false, FONT_CHAT); @@ -2499,8 +2499,8 @@ static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear) // draw the loading plaque loadingscreenpic = Draw_CachePic_Flags (loadingscreenpic_number ? va(vabuf, sizeof(vabuf), "%s%d", scr_loadingscreen_picture.string, loadingscreenpic_number+1) : scr_loadingscreen_picture.string, loadingscreenpic_number ? CACHEPICFLAG_NOTPERSISTENT : 0); - w = loadingscreenpic->width; - h = loadingscreenpic->height; + w = Draw_GetPicWidth(loadingscreenpic); + h = Draw_GetPicHeight(loadingscreenpic); // apply scale w *= scr_loadingscreen_scale.value; diff --git a/cl_video.c b/cl_video.c index bcaa85b1..7543c306 100644 --- a/cl_video.c +++ b/cl_video.c @@ -1,6 +1,5 @@ #include "quakedef.h" -#include "cl_dyntexture.h" #include "cl_video.h" // cvars @@ -72,22 +71,20 @@ static qboolean OpenStream( clvideo_t * video ) static void VideoUpdateCallback(rtexture_t *rt, void *data) { clvideo_t *video = (clvideo_t *) data; - R_UpdateTexture( video->cpif.tex, (unsigned char *)video->imagedata, 0, 0, 0, video->cpif.width, video->cpif.height, 1 ); + Draw_NewPic(video->name, video->width, video->height, (unsigned char *)video->imagedata, TEXTYPE_BGRA, TEXF_CLAMP); } static void LinkVideoTexture( clvideo_t *video ) { - video->cpif.tex = R_LoadTexture2D( cl_videotexturepool, video->cpif.name, video->cpif.width, video->cpif.height, NULL, TEXTYPE_BGRA, TEXF_PERSISTENT | TEXF_CLAMP, -1, NULL ); - R_MakeTextureDynamic( video->cpif.tex, VideoUpdateCallback, video ); - CL_LinkDynTexture( video->cpif.name, video->cpif.tex ); + video->cachepic = Draw_NewPic(video->name, video->width, video->height, NULL, TEXTYPE_BGRA, TEXF_CLAMP); + // make R_GetTexture() call our VideoUpdateCallback + R_MakeTextureDynamic(Draw_GetPicTexture(video->cachepic), VideoUpdateCallback, video); } static void UnlinkVideoTexture( clvideo_t *video ) { - CL_UnlinkDynTexture( video->cpif.name ); - // free the texture - R_FreeTexture( video->cpif.tex ); - video->cpif.tex = NULL; + // free the texture (this does not destroy the cachepic_t, which is eternal) + Draw_FreePic(video->name); // free the image data Mem_Free( video->imagedata ); } @@ -119,7 +116,7 @@ static qboolean WakeVideo( clvideo_t * video ) return false; } - video->imagedata = Mem_Alloc( cls.permanentmempool, video->cpif.width * video->cpif.height * cl_videobytesperpixel ); + video->imagedata = Mem_Alloc( cls.permanentmempool, video->width * video->height * cl_videobytesperpixel ); LinkVideoTexture( video ); // update starttime @@ -217,11 +214,12 @@ static void LoadSubtitles( clvideo_t *video, const char *subtitlesfile ) static clvideo_t* OpenVideo( clvideo_t *video, const char *filename, const char *name, int owner, const char *subtitlesfile ) { - strlcpy( video->filename, filename, sizeof(video->filename) ); + strlcpy(video->filename, filename, sizeof(video->filename)); + dpsnprintf(video->name, sizeof(video->name), CLVIDEOPREFIX "%s", name); video->ownertag = owner; if( strncmp( name, CLVIDEOPREFIX, sizeof( CLVIDEOPREFIX ) - 1 ) ) return NULL; - strlcpy( video->cpif.name, name, sizeof(video->cpif.name) ); + video->cachepic = Draw_CachePic_Flags(name, CACHEPICFLAG_NOTPERSISTENT | CACHEPICFLAG_QUIET); if( !OpenStream( video ) ) return NULL; @@ -232,9 +230,9 @@ static clvideo_t* OpenVideo( clvideo_t *video, const char *filename, const char video->lasttime = realtime; video->subtitles = 0; - video->cpif.width = video->getwidth( video->stream ); - video->cpif.height = video->getheight( video->stream ); - video->imagedata = Mem_Alloc( cls.permanentmempool, video->cpif.width * video->cpif.height * cl_videobytesperpixel ); + video->width = video->getwidth( video->stream ); + video->height = video->getheight( video->stream ); + video->imagedata = Mem_Alloc( cls.permanentmempool, video->width * video->height * cl_videobytesperpixel ); LinkVideoTexture( video ); // VorteX: load simple subtitle_text file @@ -289,7 +287,7 @@ clvideo_t *CL_GetVideoByName( const char *name ) for( i = 0 ; i < cl_num_videos ; i++ ) if( cl_videos[ i ].state != CLVIDEO_UNUSED - && !strcmp( cl_videos[ i ].cpif.name , name ) ) + && !strcmp( cl_videos[ i ].name , name ) ) break; if( i != cl_num_videos ) return CL_GetVideoBySlot( i ); @@ -387,7 +385,7 @@ void CL_Video_Frame(void) { do { video->framenum++; - if (video->decodeframe(video->stream, video->imagedata, cl_videormask, cl_videogmask, cl_videobmask, cl_videobytesperpixel, cl_videobytesperpixel * video->cpif.width)) + if (video->decodeframe(video->stream, video->imagedata, cl_videormask, cl_videogmask, cl_videobmask, cl_videobytesperpixel, cl_videobytesperpixel * video->width)) { // finished? CL_RestartVideo(video); @@ -396,7 +394,7 @@ void CL_Video_Frame(void) return; } } while(video->framenum < destframe); - R_MarkDirtyTexture(video->cpif.tex); + R_MarkDirtyTexture(Draw_GetPicTexture(video->cachepic)); } } } @@ -557,12 +555,12 @@ void CL_DrawVideo(void) // draw video if (v_glslgamma_video.value >= 1) - DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, 0); + DrawQ_SuperPic(px, py, video->cachepic, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, 0); else { - DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, DRAWFLAG_NOGAMMA); + DrawQ_SuperPic(px, py, video->cachepic, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, DRAWFLAG_NOGAMMA); if (v_glslgamma_video.value > 0.0) - DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, v_glslgamma_video.value, st[2], st[3], b, b, b, v_glslgamma_video.value, st[4], st[5], b, b, b, v_glslgamma_video.value, st[6], st[7], b, b, b, v_glslgamma_video.value, 0); + DrawQ_SuperPic(px, py, video->cachepic, sx, sy, st[0], st[1], b, b, b, v_glslgamma_video.value, st[2], st[3], b, b, b, v_glslgamma_video.value, st[4], st[5], b, b, b, v_glslgamma_video.value, st[6], st[7], b, b, b, v_glslgamma_video.value, 0); } #ifndef USE_GLES2 @@ -600,13 +598,12 @@ void CL_DrawVideo(void) void CL_VideoStart(char *filename, const char *subtitlesfile) { - char vabuf[1024]; Host_StartVideo(); if( cl_videos->state != CLVIDEO_UNUSED ) CL_CloseVideo( cl_videos ); // already contains video/ - if( !OpenVideo( cl_videos, filename, va(vabuf, sizeof(vabuf), CLDYNTEXTUREPREFIX "%s", filename ), 0, subtitlesfile ) ) + if( !OpenVideo( cl_videos, filename, filename, 0, subtitlesfile ) ) return; // expand the active range to include the new entry cl_num_videos = max(cl_num_videos, 1); diff --git a/cl_video.h b/cl_video.h index 97960b89..e96e2a47 100644 --- a/cl_video.h +++ b/cl_video.h @@ -2,10 +2,7 @@ #ifndef CL_VIDEO_H #define CL_VIDEO_H -#include "cl_dyntexture.h" - -// yields DYNAMIC_TEXTURE_PATH_PREFIX CLVIDEOPREFIX video name for a path -#define CLVIDEOPREFIX CLDYNTEXTUREPREFIX "video/" +#define CLVIDEOPREFIX "video/" #define CLTHRESHOLD 2.0 #define MENUOWNER 1 @@ -46,7 +43,11 @@ typedef struct clvideo_s void *imagedata; - cachepic_t cpif; + // cachepic holds the relevant texture_t and we simply update the texture as needed + cachepic_t *cachepic; + char name[MAX_QPATH]; // name of this video UI element (not the filename) + int width; + int height; // VorteX: subtitles array int subtitles; diff --git a/clvm_cmds.c b/clvm_cmds.c index 54848d8e..27d247f7 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -1714,13 +1714,11 @@ static void VM_CL_ReadPicture (prvm_prog_t *prog) // if yes, it is used and the data is discarded // if not, the (low quality) data is used to build a new texture, whose name will get returned - pic = Draw_CachePic_Flags (name, CACHEPICFLAG_NOTPERSISTENT); + pic = Draw_CachePic_Flags(name, CACHEPICFLAG_NOTPERSISTENT | CACHEPICFLAG_FAILONMISSING); if(size) { - if(pic->tex == r_texture_notexture) - pic->tex = NULL; // don't overwrite the notexture by Draw_NewPic - if(pic->tex && !cl_readpicture_force.integer) + if (Draw_IsPicLoaded(pic) && !cl_readpicture_force.integer) { // texture found and loaded // skip over the jpeg as we don't need it @@ -1735,7 +1733,7 @@ static void VM_CL_ReadPicture (prvm_prog_t *prog) MSG_ReadBytes(&cl_message, size, buf); data = JPEG_LoadImage_BGRA(buf, size, NULL); Mem_Free(buf); - Draw_NewPic(name, image_width, image_height, false, data); + Draw_NewPic(name, image_width, image_height, data, TEXTYPE_BGRA, TEXF_CLAMP); Mem_Free(data); } } @@ -3479,7 +3477,7 @@ static void VM_CL_R_PolygonBegin (prvm_prog_t *prog) while(sf && sf->textureflags != tf); if(!sf || !sf->base) - sf = R_SkinFrame_LoadExternal(picname, tf, true); + sf = R_SkinFrame_LoadExternal(picname, tf, true, true); if(sf) R_SkinFrame_MarkUsed(sf); diff --git a/console.c b/console.c index 51a1a123..6eac13e1 100644 --- a/console.c +++ b/console.c @@ -1975,7 +1975,7 @@ void Con_DrawConsole (int lines) conbackpic = scr_conbrightness.value >= 0.01f ? Draw_CachePic_Flags("gfx/conback", (sx != 0 || sy != 0) ? CACHEPICFLAG_NOCLAMP : 0) : NULL; sx *= realtime; sy *= realtime; sx -= floor(sx); sy -= floor(sy); - if (conbackpic && conbackpic->tex != r_texture_notexture) + if (Draw_IsPicLoaded(conbackpic)) DrawQ_SuperPic(0, lines - vid_conheight.integer, conbackpic, vid_conwidth.integer, vid_conheight.integer, 0 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, 1 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, @@ -1992,7 +1992,7 @@ void Con_DrawConsole (int lines) conbackpic = Draw_CachePic_Flags("gfx/conback2", (sx != 0 || sy != 0) ? CACHEPICFLAG_NOCLAMP : 0); sx *= realtime; sy *= realtime; sx -= floor(sx); sy -= floor(sy); - if(conbackpic && conbackpic->tex != r_texture_notexture) + if(Draw_IsPicLoaded(conbackpic)) DrawQ_SuperPic(0, lines - vid_conheight.integer, conbackpic, vid_conwidth.integer, vid_conheight.integer, 0 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, 1 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, @@ -2007,7 +2007,7 @@ void Con_DrawConsole (int lines) conbackpic = Draw_CachePic_Flags("gfx/conback3", (sx != 0 || sy != 0) ? CACHEPICFLAG_NOCLAMP : 0); sx *= realtime; sy *= realtime; sx -= floor(sx); sy -= floor(sy); - if(conbackpic && conbackpic->tex != r_texture_notexture) + if(Draw_IsPicLoaded(conbackpic)) DrawQ_SuperPic(0, lines - vid_conheight.integer, conbackpic, vid_conwidth.integer, vid_conheight.integer, 0 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, 1 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, diff --git a/darkplaces-dedicated-vs2017.vcxproj b/darkplaces-dedicated-vs2017.vcxproj index fd982c92..9e422ea3 100644 --- a/darkplaces-dedicated-vs2017.vcxproj +++ b/darkplaces-dedicated-vs2017.vcxproj @@ -195,7 +195,6 @@ - @@ -289,7 +288,6 @@ - diff --git a/darkplaces-sdl2-vs2017.vcxproj b/darkplaces-sdl2-vs2017.vcxproj index 12b5f8ab..77b60e1f 100644 --- a/darkplaces-sdl2-vs2017.vcxproj +++ b/darkplaces-sdl2-vs2017.vcxproj @@ -201,7 +201,6 @@ - @@ -300,7 +299,6 @@ - diff --git a/darkplaces-wgl-vs2017.vcxproj b/darkplaces-wgl-vs2017.vcxproj index 631a2b27..67ead0d3 100644 --- a/darkplaces-wgl-vs2017.vcxproj +++ b/darkplaces-wgl-vs2017.vcxproj @@ -199,7 +199,6 @@ - @@ -298,7 +297,6 @@ - diff --git a/draw.h b/draw.h index 6ac5c39b..59470b6e 100644 --- a/draw.h +++ b/draw.h @@ -24,31 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef DRAW_H #define DRAW_H -// FIXME: move this stuff to cl_screen -typedef struct cachepic_s -{ - // size of pic - int width, height; - // this flag indicates that it should be loaded and unloaded on demand - int autoload; - // texture flags to upload with - int texflags; - // texture may be freed after a while - int lastusedframe; - // renderer texture to use - rtexture_t *tex; - // used for hash lookups - struct cachepic_s *chain; - // flags - CACHEPICFLAG_NEWPIC for example - unsigned int flags; - // has alpha? - qboolean hasalpha; - // name of pic - char name[MAX_QPATH]; - // allow to override/free the texture - qboolean allow_free_tex; -} -cachepic_t; +typedef struct cachepic_s cachepic_t; typedef enum cachepicflags_e { @@ -58,7 +34,8 @@ typedef enum cachepicflags_e CACHEPICFLAG_NOCLAMP = 8, CACHEPICFLAG_NEWPIC = 16, // disables matching texflags check, because a pic created with Draw_NewPic should not be subject to that CACHEPICFLAG_MIPMAP = 32, - CACHEPICFLAG_NEAREST = 64 // force nearest filtering instead of linear + CACHEPICFLAG_NEAREST = 64, // force nearest filtering instead of linear + CACHEPICFLAG_FAILONMISSING = 128 // return NULL if the pic has no texture } cachepicflags_t; @@ -67,8 +44,8 @@ void Draw_Frame (void); cachepic_t *Draw_CachePic_Flags (const char *path, unsigned int cachepicflags); cachepic_t *Draw_CachePic (const char *path); // standard function with no options, used throughout engine // create or update a pic's image -cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels); -// free the texture memory used by a pic +cachepic_t *Draw_NewPic(const char *picname, int width, int height, unsigned char *pixels, textype_t textype, int texflags); +// free the texture memory used by a pic (the cachepic_t itself is eternal) void Draw_FreePic(const char *picname); // a triangle mesh.. @@ -113,7 +90,7 @@ typedef struct ft2_settings_s #define MAX_FONT_FALLBACKS 3 typedef struct dp_font_s { - rtexture_t *tex; + cachepic_t *pic; float width_of[256]; // width_of[0] == max width of any char; 1.0f is base width (1/16 of texture width); therefore, all widths have to be <= 1 (does not include scale) float maxwidth; // precalculated max width of the font (includes scale) char texpath[MAX_QPATH]; @@ -197,6 +174,11 @@ void DrawQ_Finish(void); void DrawQ_ProcessDrawFlag(int flags, qboolean alpha); // sets GL_DepthMask and GL_BlendFunc void DrawQ_RecalcView(void); // use this when changing r_refdef.view.* from e.g. csqc + +const char *Draw_GetPicName(cachepic_t *pic); +int Draw_GetPicWidth(cachepic_t *pic); +int Draw_GetPicHeight(cachepic_t *pic); +qboolean Draw_IsPicLoaded(cachepic_t *pic); rtexture_t *Draw_GetPicTexture(cachepic_t *pic); extern rtexturepool_t *drawtexturepool; // used by ft2.c diff --git a/ft2.c b/ft2.c index e30c22e6..6ae09792 100644 --- a/ft2.c +++ b/ft2.c @@ -1332,7 +1332,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET); if (developer_font.integer) { - if (map->pic->tex == r_texture_notexture) + if (!Draw_IsPicLoaded(map->pic)) Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize); else Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize); @@ -1348,7 +1348,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ map->sfy = mapstart->sfy; pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel; - if (map->pic->tex == r_texture_notexture) + if (!Draw_IsPicLoaded(map->pic)) { data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch); if (!data) @@ -1624,16 +1624,12 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ map->glyphs[mapch].image = false; } - if (map->pic->tex == r_texture_notexture) + if (!Draw_IsPicLoaded(map->pic)) { int w = map->glyphSize * FONT_CHARS_PER_LINE; int h = map->glyphSize * FONT_CHAR_LINES; - rtexture_t *tex; - // abuse the Draw_CachePic system to keep track of this texture - tex = R_LoadTexture2D(drawtexturepool, map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0), -1, NULL); - // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture - if (tex) - map->pic->tex = tex; + // update the pic returned by Draw_CachePic_Flags earlier to contain our texture + Draw_NewPic(map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0)); if (r_font_diskcache.integer >= 1) { @@ -1649,8 +1645,8 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ } Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "%s.tga", map_identifier), w, h, data); #ifndef USE_GLES2 - if (r_font_compress.integer && qglGetCompressedTexImageARB && tex) - R_SaveTextureDDSFile(tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true); + if (r_font_compress.integer && qglGetCompressedTexImageARB && Draw_IsPicLoaded(map->pic)) + R_SaveTextureDDSFile(Draw_GetPicTexture(map->pic), va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true); #endif } } @@ -1658,7 +1654,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ if(data) Mem_Free(data); - if (map->pic->tex == r_texture_notexture) + if (!Draw_IsPicLoaded(map->pic)) { // if the first try isn't successful, keep it with a broken texture // otherwise we retry to load it every single frame where ft2 rendering is used diff --git a/gl_draw.c b/gl_draw.c index 77c873c3..4e0bfd6f 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -23,11 +23,30 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "wad.h" #include "cl_video.h" -#include "cl_dyntexture.h" #include "ft2.h" #include "ft2_fontdefs.h" +struct cachepic_s +{ + // size of pic + int width, height; + // this flag indicates that it should be loaded and unloaded on demand + int autoload; + // texture flags to upload with + int texflags; + // texture may be freed after a while + int lastusedframe; + // renderable texture + skinframe_t *skinframe; + // used for hash lookups + struct cachepic_s *chain; + // flags - CACHEPICFLAG_NEWPIC for example + unsigned int flags; + // name of pic + char name[MAX_QPATH]; +}; + dp_fonts_t dp_fonts; static mempool_t *fonts_mempool = NULL; @@ -48,260 +67,12 @@ cvar_t r_nearest_conchars = {CVAR_SAVE, "r_nearest_conchars", "0", "use nearest //============================================================================= /* Support Routines */ -#define FONT_FILESIZE 13468 static cachepic_t *cachepichash[CACHEPICHASHSIZE]; static cachepic_t cachepics[MAX_CACHED_PICS]; static int numcachepics; rtexturepool_t *drawtexturepool; -static const unsigned char concharimage[FONT_FILESIZE] = -{ -#include "lhfont.h" -}; - -static rtexture_t *draw_generateconchars(void) -{ - int i; - unsigned char *data; - double random; - rtexture_t *tex; - - data = LoadTGA_BGRA (concharimage, FONT_FILESIZE, NULL); -// Gold numbers - for (i = 0;i < 8192;i++) - { - random = lhrandom (0.0,1.0); - data[i*4+3] = data[i*4+0]; - data[i*4+2] = 83 + (unsigned char)(random * 64); - data[i*4+1] = 71 + (unsigned char)(random * 32); - data[i*4+0] = 23 + (unsigned char)(random * 16); - } -// White chars - for (i = 8192;i < 32768;i++) - { - random = lhrandom (0.0,1.0); - data[i*4+3] = data[i*4+0]; - data[i*4+2] = 95 + (unsigned char)(random * 64); - data[i*4+1] = 95 + (unsigned char)(random * 64); - data[i*4+0] = 95 + (unsigned char)(random * 64); - } -// Gold numbers - for (i = 32768;i < 40960;i++) - { - random = lhrandom (0.0,1.0); - data[i*4+3] = data[i*4+0]; - data[i*4+2] = 83 + (unsigned char)(random * 64); - data[i*4+1] = 71 + (unsigned char)(random * 32); - data[i*4+0] = 23 + (unsigned char)(random * 16); - } -// Red chars - for (i = 40960;i < 65536;i++) - { - random = lhrandom (0.0,1.0); - data[i*4+3] = data[i*4+0]; - data[i*4+2] = 96 + (unsigned char)(random * 64); - data[i*4+1] = 43 + (unsigned char)(random * 32); - data[i*4+0] = 27 + (unsigned char)(random * 32); - } - -#if 0 - Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, data); -#endif - - tex = R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, data, TEXTYPE_BGRA, TEXF_ALPHA | (r_nearest_conchars.integer ? TEXF_FORCENEAREST : 0), -1, NULL); - Mem_Free(data); - return tex; -} - -static rtexture_t *draw_generateditherpattern(void) -{ - int x, y; - unsigned char pixels[8][8]; - for (y = 0;y < 8;y++) - for (x = 0;x < 8;x++) - pixels[y][x] = ((x^y) & 4) ? 254 : 0; - return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, pixels[0], TEXTYPE_PALETTE, TEXF_FORCENEAREST, -1, palette_bgra_transparent); -} - -typedef struct embeddedpic_s -{ - const char *name; - int width; - int height; - const char *pixels; -} -embeddedpic_t; - -static const embeddedpic_t embeddedpics[] = -{ - { - "gfx/prydoncursor001", 16, 16, - "477777774......." - "77.....6........" - "7.....6........." - "7....6.........." - "7.....6........." - "7..6...6........" - "7.6.6...6......." - "76...6...6......" - "4.....6.6......." - ".......6........" - "................" - "................" - "................" - "................" - "................" - "................" - }, - { - "ui/mousepointer", 16, 16, - "477777774......." - "77.....6........" - "7.....6........." - "7....6.........." - "7.....6........." - "7..6...6........" - "7.6.6...6......." - "76...6...6......" - "4.....6.6......." - ".......6........" - "................" - "................" - "................" - "................" - "................" - "................" - }, - { - "gfx/crosshair1", 16, 16, - "................" - "................" - "................" - "...33......33..." - "...355....553..." - "....577..775...." - ".....77..77....." - "................" - "................" - ".....77..77....." - "....577..775...." - "...355....553..." - "...33......33..." - "................" - "................" - "................" - }, - { - "gfx/crosshair2", 16, 16, - "................" - "................" - "................" - "...3........3..." - "....5......5...." - ".....7....7....." - "......7..7......" - "................" - "................" - "......7..7......" - ".....7....7....." - "....5......5...." - "...3........3..." - "................" - "................" - "................" - }, - { - "gfx/crosshair3", 16, 16, - "................" - ".......77......." - ".......77......." - "................" - "................" - ".......44......." - ".......44......." - ".77..44..44..77." - ".77..44..44..77." - ".......44......." - ".......44......." - "................" - "................" - ".......77......." - ".......77......." - "................" - }, - { - "gfx/crosshair4", 16, 16, - "................" - "................" - "................" - "................" - "................" - "................" - "................" - "................" - "........7777777." - "........752....." - "........72......" - "........7......." - "........7......." - "........7......." - "........7......." - "................" - }, - { - "gfx/crosshair5", 8, 8, - "........" - "........" - "....7..." - "........" - "..7.7.7." - "........" - "....7..." - "........" - }, - { - "gfx/crosshair6", 2, 2, - "77" - "77" - }, - { - "gfx/crosshair7", 16, 16, - "................" - ".3............3." - "..5...2332...5.." - "...7.3....3.7..." - "....7......7...." - "...3.7....7.3..." - "..2...7..7...2.." - "..3..........3.." - "..3..........3.." - "..2...7..7...2.." - "...3.7....7.3..." - "....7......7...." - "...7.3....3.7..." - "..5...2332...5.." - ".3............3." - "................" - }, - {NULL, 0, 0, NULL} -}; - -static rtexture_t *draw_generatepic(const char *name, qboolean quiet) -{ - const embeddedpic_t *p; - for (p = embeddedpics;p->name;p++) - if (!strcmp(name, p->name)) - return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA, -1, palette_bgra_embeddedpic); - if (!strcmp(name, "gfx/conchars")) - return draw_generateconchars(); - if (!strcmp(name, "gfx/colorcontrol/ditherpattern")) - return draw_generateditherpattern(); - if (!quiet) - Con_DPrintf("Draw_CachePic: failed to load %s\n", name); - return r_texture_notexture; -} - int draw_frame = 1; /* @@ -313,17 +84,8 @@ Draw_CachePic cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) { int crc, hashkey; - unsigned char *pixels = NULL; cachepic_t *pic; - fs_offset_t lmpsize; - unsigned char *lmpdata; - char lmpname[MAX_QPATH]; int texflags; - int j; - qboolean ddshasalpha; - float ddsavgcolor[4]; - qboolean loaded = false; - char vabuf[1024]; texflags = TEXF_ALPHA; if (!(cachepicflags & CACHEPICFLAG_NOCLAMP)) @@ -340,20 +102,24 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE; for (pic = cachepichash[hashkey];pic;pic = pic->chain) { - if (!strcmp (path, pic->name)) + if (!strcmp(path, pic->name)) { // if it was created (or replaced) by Draw_NewPic, just return it - if(pic->flags & CACHEPICFLAG_NEWPIC) + if (pic->flags & CACHEPICFLAG_NEWPIC) + { + if (pic->skinframe) + R_SkinFrame_MarkUsed(pic->skinframe); + pic->lastusedframe = draw_frame; return pic; + } if (!((pic->texflags ^ texflags) & ~(TEXF_COMPRESS | TEXF_MIPMAP))) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag, and ignore TEXF_MIPMAP because QC specifies that { - if(!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT)) - { - if(pic->tex) - pic->autoload = false; // persist it - else - goto reload; // load it below, and then persist - } + if (!pic->skinframe || !pic->skinframe->base) + goto reload; + if (!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT)) + pic->autoload = false; // caller is making this pic persistent + R_SkinFrame_MarkUsed(pic->skinframe); + pic->lastusedframe = draw_frame; return pic; } } @@ -373,138 +139,26 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) cachepichash[hashkey] = pic; reload: - // TODO why does this crash? - if(pic->allow_free_tex && pic->tex) - R_PurgeTexture(pic->tex); + if (pic->skinframe) + R_SkinFrame_PurgeSkinFrame(pic->skinframe); - // check whether it is an dynamic texture (if so, we can directly use its texture handler) pic->flags = cachepicflags; - pic->tex = CL_GetDynTexture( path ); - // if so, set the width/height, too - if( pic->tex ) { - pic->allow_free_tex = false; - pic->width = R_TextureWidth(pic->tex); - pic->height = R_TextureHeight(pic->tex); - // we're done now (early-out) - return pic; - } - - pic->allow_free_tex = true; - - pic->hasalpha = true; // assume alpha unless we know it has none pic->texflags = texflags; - pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT); + pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT) != 0; pic->lastusedframe = draw_frame; - // load a high quality image from disk if possible - if (!loaded && r_texture_dds_load.integer != 0 && (pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0, false))) - { - // note this loads even if autoload is true, otherwise we can't get the width/height - loaded = true; - pic->hasalpha = ddshasalpha; - pic->width = R_TextureWidth(pic->tex); - pic->height = R_TextureHeight(pic->tex); - } - if (!loaded && ((pixels = loadimagepixelsbgra(pic->name, false, true, false, NULL)) || (!strncmp(pic->name, "gfx/", 4) && (pixels = loadimagepixelsbgra(pic->name+4, false, true, false, NULL))))) - { - loaded = true; - pic->hasalpha = false; - if (pic->texflags & TEXF_ALPHA) - { - for (j = 3;j < image_width * image_height * 4;j += 4) - { - if (pixels[j] < 255) - { - pic->hasalpha = true; - break; - } - } - } - - pic->width = image_width; - pic->height = image_height; - if (!pic->autoload) - { - pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, image_width, image_height, pixels, vid.sRGB2D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, pic->texflags & (pic->hasalpha ? ~0 : ~TEXF_ALPHA), -1, NULL); -#ifndef USE_GLES2 - if (r_texture_dds_save.integer && qglGetCompressedTexImageARB && pic->tex) - R_SaveTextureDDSFile(pic->tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha); -#endif - } - } - if (!loaded) - { - pic->autoload = false; - // never compress the fallback images - pic->texflags &= ~TEXF_COMPRESS; - } - - // now read the low quality version (wad or lmp file), and take the pic - // size from that even if we don't upload the texture, this way the pics - // show up the right size in the menu even if they were replaced with - // higher or lower resolution versions - dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", pic->name); - if ((!strncmp(pic->name, "gfx/", 4) || (gamemode == GAME_BLOODOMNICIDE && !strncmp(pic->name, "locale/", 6))) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize))) - { - if (developer_loading.integer) - Con_Printf("loading lump \"%s\"\n", pic->name); + // load high quality image (this falls back to low quality too) + pic->skinframe = R_SkinFrame_LoadExternal(pic->name, texflags, (cachepicflags & CACHEPICFLAG_QUIET) == 0, (cachepicflags & CACHEPICFLAG_FAILONMISSING) == 0); - if (lmpsize >= 9) - { - pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216; - pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216; - // if no high quality replacement image was found, upload the original low quality texture - if (!loaded) - { - loaded = true; - pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, pic->width, pic->height, lmpdata + 8, vid.sRGB2D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_transparent); - } - } - Mem_Free(lmpdata); - } - else if ((lmpdata = W_GetLumpName (pic->name + 4))) + // get the dimensions of the image we loaded (if it was successful) + if (pic->skinframe && pic->skinframe->base) { - if (developer_loading.integer) - Con_Printf("loading gfx.wad lump \"%s\"\n", pic->name + 4); - - if (!strcmp(pic->name, "gfx/conchars")) - { - // conchars is a raw image and with color 0 as transparent instead of 255 - pic->width = 128; - pic->height = 128; - // if no high quality replacement image was found, upload the original low quality texture - if (!loaded) - { - loaded = true; - pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, 128, 128, lmpdata, vid.sRGB2D != 0 ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_font); - } - } - else - { - pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216; - pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216; - // if no high quality replacement image was found, upload the original low quality texture - if (!loaded) - { - loaded = true; - pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, pic->width, pic->height, lmpdata + 8, vid.sRGB2D != 0 ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_transparent); - } - } + pic->width = R_TextureWidth(pic->skinframe->base); + pic->height = R_TextureHeight(pic->skinframe->base); } - if (pixels) - { - Mem_Free(pixels); - pixels = NULL; - } - if (!loaded) - { - // if it's not found on disk, generate an image - pic->tex = draw_generatepic(pic->name, (cachepicflags & CACHEPICFLAG_QUIET) != 0); - pic->width = R_TextureWidth(pic->tex); - pic->height = R_TextureHeight(pic->tex); - pic->allow_free_tex = (pic->tex != r_texture_notexture); - } + // check for a low quality version of the pic and use its size if possible, to match the stock hud + Image_GetStockPicSize(pic->name, &pic->width, &pic->height); return pic; } @@ -514,38 +168,45 @@ cachepic_t *Draw_CachePic (const char *path) return Draw_CachePic_Flags (path, 0); // default to persistent! } +const char *Draw_GetPicName(cachepic_t *pic) +{ + if (pic == NULL) + return ""; + return pic->name; +} + +int Draw_GetPicWidth(cachepic_t *pic) +{ + if (pic == NULL) + return 0; + return pic->width; +} + +int Draw_GetPicHeight(cachepic_t *pic) +{ + if (pic == NULL) + return 0; + return pic->height; +} + +qboolean Draw_IsPicLoaded(cachepic_t *pic) +{ + if (pic == NULL) + return false; + if (pic->autoload && (!pic->skinframe || !pic->skinframe->base)) + pic->skinframe = R_SkinFrame_LoadExternal(pic->name, pic->texflags, false, true); + // skinframe will only be NULL if the pic was created with CACHEPICFLAG_FAILONMISSING and not found + return pic->skinframe != NULL && pic->skinframe->base != NULL; +} + rtexture_t *Draw_GetPicTexture(cachepic_t *pic) { - char vabuf[1024]; - if (pic->autoload && !pic->tex) - { - if (pic->tex == NULL && r_texture_dds_load.integer != 0) - { - qboolean ddshasalpha; - float ddsavgcolor[4]; - pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0, false); - } - if (pic->tex == NULL) - { - pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true, vid.sRGB2D); -#ifndef USE_GLES2 - if (r_texture_dds_save.integer && qglGetCompressedTexImageARB && pic->tex) - R_SaveTextureDDSFile(pic->tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha); -#endif - } - if (pic->tex == NULL && !strncmp(pic->name, "gfx/", 4)) - { - pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true, vid.sRGB2D); -#ifndef USE_GLES2 - if (r_texture_dds_save.integer && qglGetCompressedTexImageARB && pic->tex) - R_SaveTextureDDSFile(pic->tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha); -#endif - } - if (pic->tex == NULL) - pic->tex = draw_generatepic(pic->name, true); - } + if (pic == NULL) + return NULL; + if (pic->autoload && (!pic->skinframe || !pic->skinframe->base)) + pic->skinframe = R_SkinFrame_LoadExternal(pic->name, pic->texflags, false, true); pic->lastusedframe = draw_frame; - return pic->tex; + return pic->skinframe ? pic->skinframe->base : NULL; } void Draw_Frame(void) @@ -557,17 +218,12 @@ void Draw_Frame(void) return; nextpurgetime = realtime + 0.05; for (i = 0, pic = cachepics;i < numcachepics;i++, pic++) - { - if (pic->autoload && pic->tex && pic->lastusedframe < draw_frame) - { - R_FreeTexture(pic->tex); - pic->tex = NULL; - } - } + if (pic->autoload && pic->skinframe && pic->skinframe->base && pic->lastusedframe < draw_frame) + R_SkinFrame_PurgeSkinFrame(pic->skinframe); draw_frame++; } -cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra) +cachepic_t *Draw_NewPic(const char *picname, int width, int height, unsigned char *pixels_bgra, textype_t textype, int texflags) { int crc, hashkey; cachepic_t *pic; @@ -580,9 +236,11 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, u if (pic) { - if (pic->flags == CACHEPICFLAG_NEWPIC && pic->tex && pic->width == width && pic->height == height) + if (pic->flags & CACHEPICFLAG_NEWPIC && pic->skinframe && pic->skinframe->base && pic->width == width && pic->height == height) { - R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, 0, width, height, 1); + R_UpdateTexture(pic->skinframe->base, pixels_bgra, 0, 0, 0, width, height, 1); + R_SkinFrame_MarkUsed(pic->skinframe); + pic->lastusedframe = draw_frame; return pic; } } @@ -602,12 +260,15 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, u cachepichash[hashkey] = pic; } + R_SkinFrame_PurgeSkinFrame(pic->skinframe); + pic->flags = CACHEPICFLAG_NEWPIC; // disable texflags checks in Draw_CachePic + pic->flags |= (texflags & TEXF_CLAMP) ? 0 : CACHEPICFLAG_NOCLAMP; + pic->flags |= (texflags & TEXF_FORCENEAREST) ? CACHEPICFLAG_NEAREST : 0; pic->width = width; pic->height = height; - if (pic->allow_free_tex && pic->tex) - R_FreeTexture(pic->tex); - pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, (alpha ? TEXF_ALPHA : 0), -1, NULL); + pic->skinframe = R_SkinFrame_LoadInternalBGRA(picname, texflags, pixels_bgra, width, height, vid.sRGB2D); + pic->lastusedframe = draw_frame; return pic; } @@ -616,15 +277,14 @@ void Draw_FreePic(const char *picname) int crc; int hashkey; cachepic_t *pic; - // this doesn't really free the pic, but does free it's texture + // this doesn't really free the pic, but does free its texture crc = CRC_Block((unsigned char *)picname, strlen(picname)); hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE; for (pic = cachepichash[hashkey];pic;pic = pic->chain) { - if (!strcmp (picname, pic->name) && pic->tex) + if (!strcmp (picname, pic->name) && pic->skinframe) { - R_FreeTexture(pic->tex); - pic->tex = NULL; + R_SkinFrame_PurgeSkinFrame(pic->skinframe); pic->width = 0; pic->height = 0; return; @@ -677,20 +337,20 @@ void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale, Con_DPrintf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath); } - fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; - if(fnt->tex == r_texture_notexture) + fnt->pic = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0) | CACHEPICFLAG_FAILONMISSING); + if(!Draw_IsPicLoaded(fnt->pic)) { for (i = 0; i < MAX_FONT_FALLBACKS; ++i) { if (!fnt->fallbacks[i][0]) break; - fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; - if(fnt->tex != r_texture_notexture) + fnt->pic = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0) | CACHEPICFLAG_FAILONMISSING); + if(Draw_IsPicLoaded(fnt->pic)) break; } - if(fnt->tex == r_texture_notexture) + if(!Draw_IsPicLoaded(fnt->pic)) { - fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; + fnt->pic = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0)); strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile)); } else @@ -1031,7 +691,16 @@ static void gl_draw_shutdown(void) static void gl_draw_newmap(void) { + int i; font_newmap(); + + // mark all of the persistent pics so they are not purged... + for (i = 0; i < numcachepics; i++) + { + cachepic_t *pic = cachepics + i; + if (!pic->autoload && pic->skinframe) + R_SkinFrame_MarkUsed(pic->skinframe); + } } void GL_Draw_Init (void) @@ -1090,7 +759,7 @@ static void _DrawQ_SetupAndProcessDrawFlag(int flags, cachepic_t *pic, float alp _DrawQ_Setup(); if(!r_draw2d.integer && !r_draw2d_force) return; - DrawQ_ProcessDrawFlag(flags, (alpha < 1) || (pic && pic->hasalpha)); + DrawQ_ProcessDrawFlag(flags, (alpha < 1) || (pic && pic->skinframe && pic->skinframe->hasalpha)); } void DrawQ_ProcessDrawFlag(int flags, qboolean alpha) { @@ -1532,8 +1201,8 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma const float *width_of; int tw, th; - tw = R_TextureWidth(fnt->tex); - th = R_TextureHeight(fnt->tex); + tw = Draw_GetPicWidth(fnt->pic); + th = Draw_GetPicHeight(fnt->pic); if (!h) h = w; if (!h) { @@ -1570,8 +1239,8 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma // R_Mesh_ResetTextureState(); if (!fontmap) - R_Mesh_TexBind(0, fnt->tex); - R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + R_Mesh_TexBind(0, Draw_GetPicTexture(fnt->pic)); + R_SetupShader_Generic(Draw_GetPicTexture(fnt->pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); ac = color4f; at = texcoord2f; @@ -1707,7 +1376,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma at = texcoord2f; av = vertex3f; } - R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + R_SetupShader_Generic(Draw_GetPicTexture(fnt->pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); map = ft2_oldstyle_map; } } @@ -1786,7 +1455,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma break; } } - R_SetupShader_Generic(map->pic->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + R_SetupShader_Generic(Draw_GetPicTexture(map->pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); } mapch = ch - map->start; @@ -2108,7 +1777,7 @@ void DrawQ_SetClipArea(float x, float y, float width, float height) _DrawQ_Setup(); // We have to convert the con coords into real coords - // OGL uses top to bottom + // OGL uses bottom to top (origin is in bottom left) ix = (int)(0.5 + x * ((float)r_refdef.view.width / vid_conwidth.integer)) + r_refdef.view.x; iy = (int)(0.5 + y * ((float)r_refdef.view.height / vid_conheight.integer)) + r_refdef.view.y; iw = (int)(0.5 + width * ((float)r_refdef.view.width / vid_conwidth.integer)); diff --git a/gl_rmain.c b/gl_rmain.c index 4e35c2ed..36a45b0d 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // r_main.c #include "quakedef.h" -#include "cl_dyntexture.h" #include "r_shadow.h" #include "polygon.h" #include "image.h" @@ -3195,16 +3194,13 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc))) break; - if (!item) { - rtexture_t *dyntexture; - // check whether its a dynamic texture - dyntexture = CL_GetDynTexture( basename ); - if (!add && !dyntexture) + if (!item) + { + if (!add) return NULL; item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array); memset(item, 0, sizeof(*item)); strlcpy(item->basename, basename, sizeof(item->basename)); - item->base = dyntexture; // either NULL or dyntexture handle item->textureflags = textureflags & ~TEXF_FORCE_RELOAD; item->comparewidth = comparewidth; item->compareheight = compareheight; @@ -3214,21 +3210,10 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid } else if (textureflags & TEXF_FORCE_RELOAD) { - rtexture_t *dyntexture; - // check whether its a dynamic texture - dyntexture = CL_GetDynTexture( basename ); - if (!add && !dyntexture) + if (!add) return NULL; R_SkinFrame_PurgeSkinFrame(item); } - else if( item->base == NULL ) - { - rtexture_t *dyntexture; - // check whether its a dynamic texture - // this only needs to be done because Purge doesnt delete skinframes - only sets the texture pointers to NULL and we need to restore it before returing.. [11/29/2007 Black] - dyntexture = CL_GetDynTexture( basename ); - item->base = dyntexture; // either NULL or dyntexture handle - } R_SkinFrame_MarkUsed(item); return item; @@ -3270,7 +3255,7 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid } extern cvar_t gl_picmip; -skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain) +skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture) { int j; unsigned char *pixels; @@ -3304,6 +3289,8 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false))) { basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel); + if (basepixels == NULL && fallbacknotexture) + basepixels = Image_GenerateNoTexture(); if (basepixels == NULL) return NULL; } @@ -3729,7 +3716,7 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co Con_Printf("loading embedded 8bit image \"%s\"\n", name); skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette); - if (textureflags & TEXF_ALPHA) + if ((textureflags & TEXF_ALPHA) && alphapalette) { for (i = 0;i < width * height;i++) { @@ -3777,6 +3764,73 @@ skinframe_t *R_SkinFrame_LoadMissing(void) return skinframe; } +skinframe_t *R_SkinFrame_LoadNoTexture(void) +{ + int x, y; + static unsigned char pix[16][16][4]; + + if (cls.state == ca_dedicated) + return NULL; + + // this makes a light grey/dark grey checkerboard texture + if (!pix[0][0][3]) + { + for (y = 0; y < 16; y++) + { + for (x = 0; x < 16; x++) + { + if ((y < 8) ^ (x < 8)) + { + pix[y][x][0] = 128; + pix[y][x][1] = 128; + pix[y][x][2] = 128; + pix[y][x][3] = 255; + } + else + { + pix[y][x][0] = 64; + pix[y][x][1] = 64; + pix[y][x][2] = 64; + pix[y][x][3] = 255; + } + } + } + } + + return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false); +} + +skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB) +{ + skinframe_t *skinframe; + if (cls.state == ca_dedicated) + return NULL; + // if already loaded just return it, otherwise make a new skinframe + skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true); + if (skinframe->base) + return skinframe; + textureflags &= ~TEXF_FORCE_RELOAD; + skinframe->stain = NULL; + skinframe->merged = NULL; + skinframe->base = NULL; + skinframe->pants = NULL; + skinframe->shirt = NULL; + skinframe->nmap = NULL; + skinframe->gloss = NULL; + skinframe->glow = NULL; + skinframe->fog = NULL; + skinframe->reflect = NULL; + skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0; + // if no data was provided, then clearly the caller wanted to get a blank skinframe + if (!tex) + return NULL; + if (developer_loading.integer) + Con_Printf("loading 32bit skin \"%s\"\n", name); + skinframe->base = skinframe->merged = tex; + Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder + return skinframe; +} + //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"}; typedef struct suffixinfo_s { diff --git a/gl_rsurf.c b/gl_rsurf.c index 0bec0bde..130e7453 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -1577,7 +1577,7 @@ static void R_ReplaceWorldTexture (void) { if(/*t->width && !strcasecmp(t->name, r)*/ matchpattern( t->name, r, true ) ) { - if ((skinframe = R_SkinFrame_LoadExternal(newt, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PICMIP, true))) + if ((skinframe = R_SkinFrame_LoadExternal(newt, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PICMIP, true, false))) { // t->skinframes[0] = skinframe; t->currentskinframe = skinframe; diff --git a/gl_textures.c b/gl_textures.c index 29d325ed..06373653 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -324,7 +324,7 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha_compress : &textype_sRGB_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha : &textype_sRGB_bgra); #endif default: - Host_Error("R_GetTexTypeInfo: unknown texture format"); + Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags); break; } return NULL; diff --git a/image.c b/image.c index 1f15a2fc..9e3f0fd6 100644 --- a/image.c +++ b/image.c @@ -4,10 +4,13 @@ #include "jpeg.h" #include "image_png.h" #include "r_shadow.h" +#include "wad.h" int image_width; int image_height; +static unsigned char *Image_GetEmbeddedPicBGRA(const char *name); + static void Image_CopyAlphaFromBlueBGRA(unsigned char *outpixels, const unsigned char *inpixels, int w, int h) { int i, n; @@ -834,6 +837,78 @@ qboolean LoadWAL_GetMetadata(const unsigned char *f, int filesize, int *retwidth return true; } +// gfx/* wad lumps and gfx/*.lmp files are simply width and height and paletted pixels, with color 255 as transparent +static unsigned char* LoadLMP_BGRA(const unsigned char *f, int filesize, int *miplevel) +{ + unsigned char *image_buffer; + int i; + + if (filesize < 9) + { + Con_Print("Bad lmp file\n"); + return NULL; + } + + image_width = f[0] + f[1] * 0x100 + f[2] * 0x10000 + f[3] * 0x1000000; + image_height = f[4] + f[5] * 0x100 + f[6] * 0x10000 + f[7] * 0x1000000; + + if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0 || image_width * image_height > filesize - 8) + { + Con_Print("Bad lmp file\n"); + return NULL; + } + + image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height * 4); + if (!image_buffer) + { + Con_Printf("LoadLMP: not enough memory for %i by %i image\n", image_width, image_height); + return NULL; + } + + for (i = 0; i < image_width * image_height; i++) + { + const unsigned char *p = (const unsigned char *)palette_bgra_transparent + 4 * f[8 + i]; + image_buffer[i * 4 + 0] = p[0]; + image_buffer[i * 4 + 1] = p[1]; + image_buffer[i * 4 + 2] = p[2]; + image_buffer[i * 4 + 3] = p[3]; + } + + return image_buffer; +} + +// gfx/conchars is a raw 128x128 image with 0 as transparent color rather than 255 +unsigned char *LoadConChars_BGRA(const unsigned char *f, int filesize, int *miplevel) +{ + unsigned char *image_buffer; + int i; + + image_width = 128; + image_height = 128; + if (image_width * image_height > filesize) + { + Con_Print("Bad lmp file\n"); + return NULL; + } + + image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height * 4); + if (!image_buffer) + { + Con_Printf("LoadConChars: not enough memory for %i by %i image\n", image_width, image_height); + return NULL; + } + + for (i = 0; i < image_width * image_height; i++) + { + const unsigned char *p = (const unsigned char *)palette_bgra_font + 4 * f[i]; + image_buffer[i * 4 + 0] = p[0]; + image_buffer[i * 4 + 1] = p[1]; + image_buffer[i * 4 + 2] = p[2]; + image_buffer[i * 4 + 3] = p[3]; + } + + return image_buffer; +} void Image_StripImageExtension (const char *in, char *out, size_t size_out) { @@ -950,6 +1025,7 @@ imageformat_t imageformats_gfx[] = {"%s.png", PNG_LoadImage_BGRA}, {"%s.jpg", JPEG_LoadImage_BGRA}, {"%s.pcx", LoadPCX_BGRA}, + {"%s.lmp", LoadLMP_BGRA}, {NULL, NULL} }; @@ -959,6 +1035,7 @@ imageformat_t imageformats_other[] = {"%s.png", PNG_LoadImage_BGRA}, {"%s.jpg", JPEG_LoadImage_BGRA}, {"%s.pcx", LoadPCX_BGRA}, + {"%s.lmp", LoadLMP_BGRA}, {NULL, NULL} }; @@ -968,7 +1045,7 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo fs_offset_t filesize; imageformat_t *firstformat, *format; unsigned char *f, *data = NULL, *data2 = NULL; - char basename[MAX_QPATH], name[MAX_QPATH], name2[MAX_QPATH], *c; + char basename[MAX_QPATH], name[MAX_QPATH], name2[MAX_QPATH], path[MAX_QPATH], afterpath[MAX_QPATH], *c; char vabuf[1024]; //if (developer_memorydebug.integer) // Mem_CheckSentinelsGlobal(); @@ -979,23 +1056,26 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo for (c = basename;*c;c++) if (*c == '*') *c = '#'; + path[0] = 0; name[0] = 0; + strlcpy(afterpath, basename, sizeof(afterpath)); if (strchr(basename, '/')) { int i; - for (i = 0;i < (int)sizeof(name)-1 && basename[i] != '/';i++) - name[i] = basename[i]; - name[i] = 0; + for (i = 0;i < (int)sizeof(path)-1 && basename[i] != '/' && basename[i];i++) + path[i] = basename[i]; + path[i] = 0; + strlcpy(afterpath, basename + i + 1, sizeof(afterpath)); } if (gamemode == GAME_TENEBRAE) firstformat = imageformats_tenebrae; else if (gamemode == GAME_DELUXEQUAKE) firstformat = imageformats_dq; - else if (!strcasecmp(name, "textures")) + else if (!strcasecmp(path, "textures")) firstformat = imageformats_textures; - else if (!strcasecmp(name, "gfx")) + else if (!strcasecmp(path, "gfx") || !strcasecmp(path, "locale")) // locale/ is used in GAME_BLOODOMNICIDE firstformat = imageformats_gfx; - else if (!strchr(basename, '/')) + else if (!path[0]) firstformat = imageformats_nopath; else firstformat = imageformats_other; @@ -1064,6 +1144,33 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name); } } + if (!strcasecmp(path, "gfx")) + { + unsigned char *lmpdata; + if ((lmpdata = W_GetLumpName(afterpath, &filesize))) + { + if (developer_loading.integer) + Con_Printf("loading gfx.wad lump \"%s\"\n", afterpath); + + int mymiplevel = miplevel ? *miplevel : 0; + if (!strcmp(afterpath, "conchars")) + { + // conchars is a raw image and with color 0 as transparent instead of 255 + data = LoadConChars_BGRA(lmpdata, filesize, &mymiplevel); + } + else + data = LoadLMP_BGRA(lmpdata, filesize, &mymiplevel); + // no cleanup after looking up a wad lump - the whole gfx.wad is loaded at once + if (data) + return data; + Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name); + } + } + + // check if the image name exists as an embedded pic + if ((data = Image_GetEmbeddedPicBGRA(basename))) + return data; + if (complain) { Con_Printf("Couldn't load %s using ", filename); @@ -1079,9 +1186,58 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo //if (developer_memorydebug.integer) // Mem_CheckSentinelsGlobal(); + return NULL; } +qboolean Image_GetStockPicSize(const char *filename, int *returnwidth, int *returnheight) +{ + unsigned char *data; + fs_offset_t filesize; + char lmppath[MAX_QPATH]; + if (!strcasecmp(filename, "gfx/conchars")) + { + *returnwidth = 128; + *returnheight = 128; + return true; + } + + dpsnprintf(lmppath, sizeof(lmppath), "%s.lmp", filename); + data = FS_LoadFile(lmppath, tempmempool, true, &filesize); + if (data) + { + if (filesize > 8) + { + int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000; + int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000; + if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768) + { + *returnwidth = w; + *returnheight = h; + Mem_Free(data); + return true; + } + } + Mem_Free(data); + } + if (!strncasecmp(filename, "gfx/", 4)) + { + data = W_GetLumpName(filename + 4, &filesize); + if (data && filesize > 8) + { + int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000; + int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000; + if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768) + { + *returnwidth = w; + *returnheight = h; + return true; + } + } + } + return false; +} + extern cvar_t gl_picmip; rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean sRGB) { @@ -1647,3 +1803,302 @@ void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned cha } } } + +static const unsigned char concharimage[] = +{ +#include "lhfont.h" +}; + +static unsigned char *Image_GenerateConChars(void) +{ + int i; + unsigned char *data; + double random; + + image_width = 256; + image_height = 256; + + data = LoadTGA_BGRA(concharimage, sizeof(concharimage), NULL); + // Gold numbers + for (i = 0; i < 8192; i++) + { + random = lhrandom(0.0, 1.0); + data[i * 4 + 3] = data[i * 4 + 0]; + data[i * 4 + 2] = 83 + (unsigned char)(random * 64); + data[i * 4 + 1] = 71 + (unsigned char)(random * 32); + data[i * 4 + 0] = 23 + (unsigned char)(random * 16); + } + // White chars + for (i = 8192; i < 32768; i++) + { + random = lhrandom(0.0, 1.0); + data[i * 4 + 3] = data[i * 4 + 0]; + data[i * 4 + 2] = 95 + (unsigned char)(random * 64); + data[i * 4 + 1] = 95 + (unsigned char)(random * 64); + data[i * 4 + 0] = 95 + (unsigned char)(random * 64); + } + // Gold numbers + for (i = 32768; i < 40960; i++) + { + random = lhrandom(0.0, 1.0); + data[i * 4 + 3] = data[i * 4 + 0]; + data[i * 4 + 2] = 83 + (unsigned char)(random * 64); + data[i * 4 + 1] = 71 + (unsigned char)(random * 32); + data[i * 4 + 0] = 23 + (unsigned char)(random * 16); + } + // Red chars + for (i = 40960; i < 65536; i++) + { + random = lhrandom(0.0, 1.0); + data[i * 4 + 3] = data[i * 4 + 0]; + data[i * 4 + 2] = 96 + (unsigned char)(random * 64); + data[i * 4 + 1] = 43 + (unsigned char)(random * 32); + data[i * 4 + 0] = 27 + (unsigned char)(random * 32); + } + +#if 0 + Image_WriteTGABGRA("gfx/generated_conchars.tga", 256, 256, data); +#endif + + return data; +} + +static unsigned char *Image_GenerateDitherPattern(void) +{ + int x, y; + unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 8 * 8 * 4); + image_width = 8; + image_height = 8; + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + data[(y * 8 + x) * 4 + 0] = ((x^y) & 4) ? 255 : 0; + data[(y * 8 + x) * 4 + 1] = ((x^y) & 4) ? 255 : 0; + data[(y * 8 + x) * 4 + 2] = ((x^y) & 4) ? 255 : 0; + data[(y * 8 + x) * 4 + 3] = 255; + } + } + return data; +} + +// also used in R_SkinFrame code +unsigned char *Image_GenerateNoTexture(void) +{ + int x, y; + unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 16 * 16 * 4); + image_width = 16; + image_height = 16; + // this makes a light grey/dark grey checkerboard texture + for (y = 0; y < 16; y++) + { + for (x = 0; x < 16; x++) + { + data[(y * 8 + x) * 4 + 0] = + data[(y * 8 + x) * 4 + 1] = + data[(y * 8 + x) * 4 + 2] = (y < 8) ^ (x < 8) ? 128 : 64; + data[(y * 8 + x) * 4 + 3] = 255; + } + } + return data; +} + +static unsigned char *Image_GenerateWhite(void) +{ + unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 1 * 1 * 4); + image_width = 1; + image_height = 1; + data[0] = data[1] = data[2] = data[3] = 255; + return data; +} + +typedef struct embeddedpic_s +{ +const char *name; +int width; +int height; +const char *pixels; +} +embeddedpic_t; + +static const embeddedpic_t embeddedpics[] = +{ + { + "gfx/prydoncursor001", 16, 16, + "477777774......." + "77.....6........" + "7.....6........." + "7....6.........." + "7.....6........." + "7..6...6........" + "7.6.6...6......." + "76...6...6......" + "4.....6.6......." + ".......6........" + "................" + "................" + "................" + "................" + "................" + "................" + }, + { + "ui/mousepointer", 16, 16, + "477777774......." + "77.....6........" + "7.....6........." + "7....6.........." + "7.....6........." + "7..6...6........" + "7.6.6...6......." + "76...6...6......" + "4.....6.6......." + ".......6........" + "................" + "................" + "................" + "................" + "................" + "................" + }, + { + "gfx/crosshair1", 16, 16, + "................" + "................" + "................" + "...33......33..." + "...355....553..." + "....577..775...." + ".....77..77....." + "................" + "................" + ".....77..77....." + "....577..775...." + "...355....553..." + "...33......33..." + "................" + "................" + "................" + }, + { + "gfx/crosshair2", 16, 16, + "................" + "................" + "................" + "...3........3..." + "....5......5...." + ".....7....7....." + "......7..7......" + "................" + "................" + "......7..7......" + ".....7....7....." + "....5......5...." + "...3........3..." + "................" + "................" + "................" + }, + { + "gfx/crosshair3", 16, 16, + "................" + ".......77......." + ".......77......." + "................" + "................" + ".......44......." + ".......44......." + ".77..44..44..77." + ".77..44..44..77." + ".......44......." + ".......44......." + "................" + "................" + ".......77......." + ".......77......." + "................" + }, + { + "gfx/crosshair4", 16, 16, + "................" + "................" + "................" + "................" + "................" + "................" + "................" + "................" + "........7777777." + "........752....." + "........72......" + "........7......." + "........7......." + "........7......." + "........7......." + "................" + }, + { + "gfx/crosshair5", 8, 8, + "........" + "........" + "....7..." + "........" + "..7.7.7." + "........" + "....7..." + "........" + }, + { + "gfx/crosshair6", 2, 2, + "77" + "77" + }, + { + "gfx/crosshair7", 16, 16, + "................" + ".3............3." + "..5...2332...5.." + "...7.3....3.7..." + "....7......7...." + "...3.7....7.3..." + "..2...7..7...2.." + "..3..........3.." + "..3..........3.." + "..2...7..7...2.." + "...3.7....7.3..." + "....7......7...." + "...7.3....3.7..." + "..5...2332...5.." + ".3............3." + "................" + }, + { NULL, 0, 0, NULL } +}; + +unsigned char *Image_GetEmbeddedPicBGRA(const char *name) +{ + const embeddedpic_t *p; + for (p = embeddedpics; p->name; p++) + { + if (!strcmp(name, p->name)) + { + int i; + unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, p->width * p->height * 4); + image_width = p->width; + image_height = p->height; + for (i = 0; i < p->width * p->height; i++) + { + const unsigned char *c = (const unsigned char *)palette_bgra_embeddedpic + 4 * p->pixels[i]; + Vector4Copy(c, data + 4 * i); + } + return data; + } + } + if (!strcmp(name, "white")) + return Image_GenerateWhite(); + if (!strcmp(name, "gfx/conchars")) + return Image_GenerateConChars(); + if (!strcmp(name, "gfx/colorcontrol/ditherpattern")) + return Image_GenerateDitherPattern(); + return NULL; +} diff --git a/image.h b/image.h index dd555a8f..21dc0123 100644 --- a/image.h +++ b/image.h @@ -4,6 +4,7 @@ extern int image_width, image_height; +unsigned char *Image_GenerateNoTexture(void); // swizzle components (even converting number of components) and flip images // (warning: input must be different than output due to non-linear read/write) @@ -25,6 +26,9 @@ unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize, int *miplevel // loads a texture, as pixel data unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans, qboolean convertsRGB, int *miplevel); +// searches for lmp and wad pics of the provided name and returns true and their dimensions if found +qboolean Image_GetStockPicSize(const char *filename, int *returnwidth, int *returnheight); + // loads an 8bit pcx image into a 296x194x8bit buffer, with cropping as needed qboolean LoadPCX_QWSkin(const unsigned char *f, int filesize, unsigned char *pixels, int outwidth, int outheight); diff --git a/libcurl.c b/libcurl.c index 72ec15d2..a1b56900 100644 --- a/libcurl.c +++ b/libcurl.c @@ -598,7 +598,7 @@ static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error pixels = decode_image(di, content_type); if(pixels) - Draw_NewPic(p, image_width, image_height, true, pixels); + Draw_NewPic(p, image_width, image_height, pixels, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP); else CLEAR_AND_RETRY(); } diff --git a/menu.c b/menu.c index 5ad0755a..aa6fb7b0 100644 --- a/menu.c +++ b/menu.c @@ -414,7 +414,7 @@ void M_Menu_Main_f (void) MAIN_ITEMS = 5; // check if the game data is missing and use a different main menu if so - m_missingdata = !forceqmenu.integer && Draw_CachePic (s)->tex == r_texture_notexture; + m_missingdata = !forceqmenu.integer && !Draw_IsPicLoaded(Draw_CachePic(s)); if (m_missingdata) MAIN_ITEMS = 2; @@ -458,7 +458,7 @@ static void M_Main_Draw (void) int y1, y2, y3; M_Background(640, 480); p = Draw_CachePic ("gfx/menu/tb-transfusion"); - M_DrawPic (640/2 - p->width/2, 40, "gfx/menu/tb-transfusion"); + M_DrawPic (640/2 - Draw_GetPicWidth(p)/2, 40, "gfx/menu/tb-transfusion"); y2 = 120; // 8 rather than MAIN_ITEMS to skip a number and not miss the last option for (y1 = 1; y1 <= 8; y1++) @@ -479,7 +479,7 @@ static void M_Main_Draw (void) M_Background(320, 200); M_DrawPic (16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/ttl_main"); - M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_main"); + M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/ttl_main"); // Nehahra if (gamemode == GAME_NEHAHRA) { @@ -758,7 +758,7 @@ static void M_SinglePlayer_Draw (void) // Some mods don't have a single player mode if (gamemode == GAME_GOODVSBAD2 || gamemode == GAME_BATTLEMECH) { - M_DrawPic ((320 - p->width) / 2, 4, "gfx/ttl_sgl"); + M_DrawPic ((320 - Draw_GetPicWidth(p)) / 2, 4, "gfx/ttl_sgl"); M_DrawTextBox (60, 8 * 8, 23, 4); if (gamemode == GAME_GOODVSBAD2) @@ -771,7 +771,7 @@ static void M_SinglePlayer_Draw (void) { int f; - M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_sgl"); + M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/ttl_sgl"); M_DrawPic (72, 32, "gfx/sp_menu"); f = (int)(realtime * 10)%6; @@ -925,7 +925,7 @@ static void M_Load_Draw (void) M_Background(320, 200); p = Draw_CachePic ("gfx/p_load"); - M_DrawPic ( (320-p->width)/2, 4, "gfx/p_load" ); + M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_load" ); for (i=0 ; i< MAX_SAVEGAMES; i++) M_Print(16, 32 + 8*i, m_filenames[i]); @@ -943,7 +943,7 @@ static void M_Save_Draw (void) M_Background(320, 200); p = Draw_CachePic ("gfx/p_save"); - M_DrawPic ( (320-p->width)/2, 4, "gfx/p_save"); + M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_save"); for (i=0 ; iwidth/2, 40, "gfx/menu/tb-episodes"); + M_DrawPic (640/2 - Draw_GetPicWidth(p)/2, 40, "gfx/menu/tb-episodes"); for (y = 0; y < EPISODE_ITEMS; y++){ M_DrawPic (0, 160 + y * 40, va(vabuf, sizeof(vabuf), "gfx/menu/episode%i", y+1)); } @@ -1110,7 +1110,7 @@ static void M_Transfusion_Skill_Draw (void) M_Background(640, 480); p = Draw_CachePic ("gfx/menu/tb-difficulty"); - M_DrawPic(640/2 - p->width/2, 40, "gfx/menu/tb-difficulty"); + M_DrawPic(640/2 - Draw_GetPicWidth(p)/2, 40, "gfx/menu/tb-difficulty"); for (y = 0; y < SKILL_ITEMS; y++) { @@ -1215,7 +1215,7 @@ static void M_MultiPlayer_Draw (void) { M_Background(640, 480); p = Draw_CachePic ("gfx/menu/tb-online"); - M_DrawPic (640/2 - p->width/2, 140, "gfx/menu/tb-online"); + M_DrawPic (640/2 - Draw_GetPicWidth(p)/2, 140, "gfx/menu/tb-online"); for (f = 1; f <= MULTIPLAYER_ITEMS; f++) M_DrawPic (0, 180 + f*40, va(vabuf, sizeof(vabuf), "gfx/menu/online%i", f)); M_DrawPic (0, 220 + m_multiplayer_cursor * 40, va(vabuf, sizeof(vabuf), "gfx/menu/online%iselected", m_multiplayer_cursor + 1)); @@ -1225,7 +1225,7 @@ static void M_MultiPlayer_Draw (void) M_DrawPic (16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/p_multi"); - M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi"); + M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_multi"); M_DrawPic (72, 32, "gfx/mp_menu"); f = (int)(realtime * 10)%6; @@ -1344,7 +1344,7 @@ static void M_Setup_Draw (void) M_DrawPic (16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/p_multi"); - M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi"); + M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_multi"); M_Print(64, 40, "Your name"); M_DrawTextBox (160, 32, 16, 1); @@ -1415,7 +1415,7 @@ static void M_Setup_Draw (void) } menuplyr_translated[i] = palette_bgra_transparent[j]; } - Draw_NewPic("gfx/menuplyr", menuplyr_width, menuplyr_height, true, (unsigned char *)menuplyr_translated); + Draw_NewPic("gfx/menuplyr", menuplyr_width, menuplyr_height, (unsigned char *)menuplyr_translated, TEXTYPE_BGRA, TEXF_CLAMP); } M_DrawPic(160, 48, "gfx/bigbox"); M_DrawPic(172, 56, "gfx/menuplyr"); @@ -1680,7 +1680,7 @@ static void M_Options_Draw (void) M_DrawPic(16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/p_option"); - M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/p_option"); m_optnum = 0; m_optcursor = options_cursor; @@ -1889,7 +1889,7 @@ static void M_Options_Effects_Draw (void) M_DrawPic(16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/p_option"); - M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/p_option"); m_optcursor = options_effects_cursor; m_optnum = 0; @@ -2036,7 +2036,7 @@ static void M_Options_Graphics_Draw (void) M_DrawPic(16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/p_option"); - M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/p_option"); m_optcursor = options_graphics_cursor; m_optnum = 0; @@ -2226,7 +2226,7 @@ static void M_Options_ColorControl_Draw (void) M_DrawPic(16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/p_option"); - M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/p_option"); m_optcursor = options_colorcontrol_cursor; m_optnum = 0; @@ -2617,7 +2617,7 @@ static void M_Keys_Draw (void) M_Background(320, 48 + 8 * numcommands); p = Draw_CachePic ("gfx/ttl_cstm"); - M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_cstm"); + M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/ttl_cstm"); if (bind_grab) M_Print(12, 32, "Press a key or button for this action"); @@ -2928,7 +2928,7 @@ static void M_Video_Draw (void) M_DrawPic(16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/vidmodes"); - M_DrawPic((320-p->width)/2, 4, "gfx/vidmodes"); + M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/vidmodes"); t = 0; @@ -3370,7 +3370,7 @@ static void M_LanConfig_Draw (void) M_DrawPic (16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/p_multi"); - basex = (320-p->width)/2; + basex = (320-Draw_GetPicWidth(p))/2; M_DrawPic (basex, 4, "gfx/p_multi"); if (StartingGame) @@ -3994,7 +3994,7 @@ void M_GameOptions_Draw (void) M_DrawPic (16, 4, "gfx/qplaque"); p = Draw_CachePic ("gfx/p_multi"); - M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi"); + M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_multi"); M_DrawTextBox (152, 32, 10, 1); M_Print(160, 40, "begin game"); @@ -4435,7 +4435,7 @@ static void M_ServerList_Draw (void) end = min(start + visible, serverlist_viewcount); p = Draw_CachePic ("gfx/p_multi"); - M_DrawPic((640 - p->width) / 2, 4, "gfx/p_multi"); + M_DrawPic((640 - Draw_GetPicWidth(p)) / 2, 4, "gfx/p_multi"); if (end > start) { for (n = start;n < end;n++) @@ -4671,7 +4671,7 @@ static void M_ModList_Draw (void) end = min(start + visible, modlist_count); p = Draw_CachePic ("gfx/p_option"); - M_DrawPic((640 - p->width) / 2, 4, "gfx/p_option"); + M_DrawPic((640 - Draw_GetPicWidth(p)) / 2, 4, "gfx/p_option"); if (end > start) { for (n = start;n < end;n++) @@ -4889,7 +4889,7 @@ void M_Draw (void) drop1 = Draw_CachePic ("gfx/menu/blooddrop1"); drop2 = Draw_CachePic ("gfx/menu/blooddrop2"); drop3 = Draw_CachePic ("gfx/menu/blooddrop3"); - for (scale_x = 0; scale_x <= vid_conwidth.integer; scale_x += p->width) { + for (scale_x = 0; scale_x <= vid_conwidth.integer; scale_x += Draw_GetPicWidth(p)) { for (scale_y = -scale_y_repeat; scale_y <= vid_conheight.integer; scale_y += scale_y_repeat) { DrawQ_Pic (scale_x + 21, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0); DrawQ_Pic (scale_x + 116, scale_y_repeat + scale_y + scale_y_rate * scale_y_repeat, drop1, 0, 0, 1, 1, 1, 1, 0); diff --git a/model_alias.c b/model_alias.c index e319582c..9fdc0800 100644 --- a/model_alias.c +++ b/model_alias.c @@ -922,45 +922,6 @@ static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *ve } } -static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe) -{ - if (cls.state == ca_dedicated) - return; - // hack - if (!skinframe) - skinframe = R_SkinFrame_LoadMissing(); - memset(texture, 0, sizeof(*texture)); - texture->currentframe = texture; - //texture->animated = false; - texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe); - texture->currentskinframe = skinframe; - //texture->backgroundnumskinframes = 0; - //texture->customblendfunc[0] = 0; - //texture->customblendfunc[1] = 0; - //texture->surfaceflags = 0; - //texture->supercontents = 0; - //texture->surfaceparms = 0; - //texture->textureflags = 0; - - texture->basematerialflags = MATERIALFLAG_WALL; - texture->basealpha = 1.0f; - if (texture->currentskinframe->hasalpha) - texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; - texture->currentmaterialflags = texture->basematerialflags; - texture->offsetmapping = OFFSETMAPPING_DEFAULT; - texture->offsetscale = 1; - texture->offsetbias = 0; - texture->specularscalemod = 1; - texture->specularpowermod = 1; - texture->surfaceflags = 0; - texture->supercontents = SUPERCONTENTS_SOLID; - if (!(texture->basematerialflags & MATERIALFLAG_BLENDED)) - texture->supercontents |= SUPERCONTENTS_OPAQUE; - texture->transparentsort = TRANSPARENTSORT_DISTANCE; - // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS - // JUST GREP FOR "specularscalemod = 1". -} - void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername) { int i; @@ -983,14 +944,14 @@ void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, con Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf)); if(developer_extra.integer) Con_DPrintf("--> got %s from skin file\n", stripbuf); - Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); + Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); break; } } if (!skinfileitem) { // don't render unmentioned meshes - Mod_BuildAliasSkinFromSkinFrame(skin, NULL); + Mod_LoadCustomMaterial(loadmodel->mempool, skin, meshname, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing()); if(developer_extra.integer) Con_DPrintf("--> skipping\n"); skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW; @@ -1002,7 +963,7 @@ void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, con if(developer_extra.integer) Con_DPrintf("--> using default\n"); Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf)); - Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); + Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); } } @@ -1030,7 +991,6 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) float *vertst; int *vertonseam, *vertremap; skinfile_t *skinfiles; - char vabuf[1024]; datapointer = (unsigned char *)buffer; pinmodel = (mdl_t *)datapointer; @@ -1299,8 +1259,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->mempool, loadmodel->name, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS)) + Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight)); datapointer += skinwidth * skinheight; totalskins++; } @@ -1308,8 +1268,12 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) // check for skins that don't exist in the model, but do exist as external images // (this was added because yummyluv kept pestering me about support for it) // TODO: support shaders here? - while ((tempskinframe = R_SkinFrame_LoadExternal(va(vabuf, sizeof(vabuf), "%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false))) + for (;;) { + dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins); + tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false); + if (!tempskinframe) + break; // expand the arrays to make room tempskinscenes = loadmodel->skinscenes; loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t)); @@ -1322,7 +1286,7 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) Mem_Free(tempaliasskins); // store the info about the new skin - Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe); + Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe); strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name)); loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins; loadmodel->skinscenes[loadmodel->numskins].framecount = 1; @@ -1487,7 +1451,7 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->num_texturesperskin = loadmodel->num_surfaces; loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME) - Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); + Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); } else { @@ -1496,7 +1460,7 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; loadmodel->num_texturesperskin = loadmodel->num_surfaces; loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); - Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL); + Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing()); } loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); diff --git a/model_brush.c b/model_brush.c index e981a59f..e6451a05 100644 --- a/model_brush.c +++ b/model_brush.c @@ -1725,7 +1725,7 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) tx->width = 16; tx->height = 16; tx->basealpha = 1.0f; - tx->materialshaderpass = tx->shaderpasses[0] = Mod_CreateShaderPass(skinframemissing); + tx->materialshaderpass = tx->shaderpasses[0] = Mod_CreateShaderPass(loadmodel->mempool, skinframemissing); tx->materialshaderpass->skinframes[0] = skinframemissing; tx->currentskinframe = skinframemissing; tx->basematerialflags = MATERIALFLAG_WALL; @@ -1826,7 +1826,7 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) // LordHavoc: backup the texture_t because q3 shader loading overwrites it backuptex = loadmodel->data_textures[i]; - if (name[0] && Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i, name, false, false, 0)) + if (name[0] && Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i, name, false, false, 0)) continue; loadmodel->data_textures[i] = backuptex; @@ -1889,9 +1889,9 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) } else { - skinframe_t *skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s/%s", mapname, tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false); + skinframe_t *skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s/%s", mapname, tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false, false); if (!skinframe) - skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s", tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false); + skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s", tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false, false); if (skinframe) tx->offsetmapping = OFFSETMAPPING_DEFAULT; // allow offsetmapping on external textures without a q3 shader if (!skinframe) @@ -4439,7 +4439,7 @@ static void Mod_Q2BSP_LoadTexinfo(sizebuf_t *sb) int q2flags = out->q2flags; unsigned char *walfile = NULL; fs_offset_t walfilesize = 0; - Mod_LoadTextureFromQ3Shader(tx, filename, true, true, TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS); + Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, tx, filename, true, true, TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS); // now read the .wal file to get metadata (even if a .tga was overriding it, we still need the wal data) walfile = FS_LoadFile(filename, tempmempool, true, &walfilesize); if (walfile) @@ -5309,7 +5309,7 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l) { out[i].surfaceflags = LittleLong(in[i].surfaceflags); out[i].supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(LittleLong(in[i].contents)); - Mod_LoadTextureFromQ3Shader(out + i, in[i].name, true, true, TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS); + Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, out + i, in[i].name, true, true, TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS); // restore the surfaceflags and supercontents out[i].surfaceflags = LittleLong(in[i].surfaceflags); out[i].supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(LittleLong(in[i].contents)); diff --git a/model_shared.c b/model_shared.c index eaa7134c..9d7d449d 100644 --- a/model_shared.c +++ b/model_shared.c @@ -2412,9 +2412,9 @@ q3shaderinfo_t *Mod_LookupQ3Shader(const char *name) return NULL; } -texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe) +texture_shaderpass_t *Mod_CreateShaderPass(mempool_t *mempool, skinframe_t *skinframe) { - texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass)); + texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass)); shaderpass->framerate = 0.0f; shaderpass->numframes = 1; shaderpass->blendfunc[0] = GL_ONE; @@ -2427,10 +2427,10 @@ texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe) return shaderpass; } -texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename) +texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool, const char *modelname, q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename) { int j; - texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass)); + texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass)); shaderpass->alphatest = layer->alphatest != 0; shaderpass->framerate = layer->framerate; shaderpass->numframes = layer->numframes; @@ -2442,21 +2442,11 @@ texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++) shaderpass->tcmods[j] = layer->tcmods[j]; for (j = 0; j < layer->numframes; j++) - { - if (cls.state == ca_dedicated) - { - shaderpass->skinframes[j] = NULL; - } - else if (!(shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false))) - { - Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for layer %i of shader ^2\"%s\"\n", loadmodel->name, layer->texturename[j], j, layerindex, texturename); - shaderpass->skinframes[j] = R_SkinFrame_LoadMissing(); - } - } + shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false, true); return shaderpass; } -qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags) +qboolean Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags) { int texflagsmask, texflagsor; qboolean success = true; @@ -2492,12 +2482,12 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool if (shader) { if (developer_loading.integer) - Con_Printf("%s: loaded shader for %s\n", loadmodel->name, name); + Con_Printf("%s: loaded shader for %s\n", modelname, name); if (shader->surfaceparms & Q3SURFACEPARM_SKY) { texture->basematerialflags = MATERIALFLAG_SKY; - if (shader->skyboxname[0]) + if (shader->skyboxname[0] && loadmodel) { // quake3 seems to append a _ to the skybox name, so this must do so as well dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname); @@ -2644,19 +2634,19 @@ nothing GL_ZERO GL_ONE // convert the main material layer // FIXME: if alphagenspecularlayer is used, we should pass a specular texture name to R_SkinFrame_LoadExternal and have it load that texture instead of the assumed name for _gloss texture if (materiallayer >= 0) - texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].dptexflags & texflagsmask) | texflagsor, texture->name); + texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].dptexflags & texflagsmask) | texflagsor, texture->name); // convert the terrain background blend layer (if any) if (terrainbackgroundlayer >= 0) - texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].dptexflags & texflagsmask) | texflagsor, texture->name); + texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].dptexflags & texflagsmask) | texflagsor, texture->name); // convert the prepass layers (if any) texture->startpreshaderpass = shaderpassindex; for (i = 0; i < endofprelayers; i++) - texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name); + texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name); texture->endpreshaderpass = shaderpassindex; texture->startpostshaderpass = shaderpassindex; // convert the postpass layers (if any) for (i = firstpostlayer; i < shader->numlayers; i++) - texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name); + texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name); texture->startpostshaderpass = shaderpassindex; } @@ -2766,25 +2756,25 @@ nothing GL_ZERO GL_ONE if (shader->dpmeshcollisions) texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS; if (shader->dpshaderkill && developer_extra.integer) - Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", loadmodel->name, name); + Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", modelname, name); } else if (!strcmp(texture->name, "noshader") || !texture->name[0]) { if (developer_extra.integer) - Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", loadmodel->name, name); + Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", modelname, name); texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; } else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw")) { if (developer_extra.integer) - Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", loadmodel->name, name); + Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", modelname, name); texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; texture->supercontents = SUPERCONTENTS_SOLID; } else { if (developer_extra.integer) - Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", loadmodel->name, texture->name); + Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", modelname, texture->name); if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW) { texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; @@ -2809,27 +2799,23 @@ nothing GL_ZERO GL_ONE { if (fallback) { - texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false)); - if (texture->materialshaderpass->skinframes[0]) - { - if (texture->materialshaderpass->skinframes[0]->hasalpha) - texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; - if (texture->q2contents) - texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(texture->q2contents); - } - else - success = false; + texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false, true)); + if (texture->materialshaderpass->skinframes[0]->hasalpha) + texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + if (texture->q2contents) + texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(texture->q2contents); } else success = false; if (!success && warnmissing) - Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", loadmodel->name, texture->name); + Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", modelname, texture->name); } } // init the animation variables texture->currentframe = texture; + texture->currentmaterialflags = texture->basematerialflags; if (!texture->materialshaderpass) - texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadMissing()); + texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, R_SkinFrame_LoadMissing()); if (!texture->materialshaderpass->skinframes[0]) texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing(); texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL; @@ -2837,13 +2823,14 @@ nothing GL_ZERO GL_ONE return success; } -void Mod_LoadCustomMaterial(texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe) +void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe) { if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY))) - Con_DPrintf("^1%s:^7 Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", loadmodel->name, texture->name); + Con_DPrintf("^1Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", texture->name); + strlcpy(texture->name, name, sizeof(texture->name)); texture->basealpha = 1.0f; - texture->basematerialflags = texture->currentmaterialflags = materialflags; + texture->basematerialflags = materialflags; texture->supercontents = supercontents; texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF; @@ -2857,17 +2844,35 @@ void Mod_LoadCustomMaterial(texture_t *texture, const char *name, int superconte // JUST GREP FOR "specularscalemod = 1". if (developer_extra.integer) - Con_DPrintf("^1%s:^7 Custom texture ^3\"%s\"\n", loadmodel->name, texture->name); - texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe); + Con_DPrintf("^1Custom texture ^3\"%s\"\n", texture->name); + if (skinframe) + texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe); // init the animation variables + texture->currentmaterialflags = texture->basematerialflags; texture->currentframe = texture; - if (!texture->materialshaderpass) - texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadMissing()); - if (!texture->materialshaderpass->skinframes[0]) - texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing(); - texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL; - texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL; + texture->currentskinframe = skinframe; + texture->backgroundcurrentskinframe = NULL; +} + +void Mod_UnloadCustomMaterial(texture_t *texture, qboolean purgeskins) +{ + int i, j; + for (i = 0; i < sizeof(texture->shaderpasses) / sizeof(texture->shaderpasses[0]); i++) + { + if (texture->shaderpasses[i]) + { + if (purgeskins) + for (j = 0; j < sizeof(texture->shaderpasses[i]->skinframes) / sizeof(skinframe_t *);j++) + if (texture->shaderpasses[i]->skinframes[j] && texture->shaderpasses[i]->skinframes[j]->base) + R_SkinFrame_PurgeSkinFrame(texture->shaderpasses[i]->skinframes[j]); + Mem_Free(texture->shaderpasses[i]); + texture->shaderpasses[i] = NULL; + } + } + texture->materialshaderpass = NULL; + texture->currentskinframe = NULL; + texture->backgroundcurrentskinframe = NULL; } skinfile_t *Mod_LoadSkinFiles(void) @@ -4609,7 +4614,7 @@ void Mod_Mesh_Reset(dp_model_t *mod) mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it } -texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name) +texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int addmaterialflags) { int i; texture_t *t; @@ -4626,35 +4631,62 @@ texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name) mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures); } t = &mod->data_textures[mod->num_textures++]; - Mod_LoadTextureFromQ3Shader(t, name, false, true, 0); + Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags); + t->basematerialflags |= addmaterialflags; + switch (defaultdrawflags & DRAWFLAG_MASK) + { + case DRAWFLAG_ADDITIVE: + t->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED; + t->currentmaterialflags = t->basematerialflags; + break; + case DRAWFLAG_MODULATE: + t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED; + t->currentmaterialflags = t->basematerialflags; + t->customblendfunc[0] = GL_DST_COLOR; + t->customblendfunc[1] = GL_ZERO; + break; + case DRAWFLAG_2XMODULATE: + t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED; + t->currentmaterialflags = t->basematerialflags; + t->customblendfunc[0] = GL_DST_COLOR; + t->customblendfunc[1] = GL_SRC_COLOR; + break; + case DRAWFLAG_SCREEN: + t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED; + t->currentmaterialflags = t->basematerialflags; + t->customblendfunc[0] = GL_ONE_MINUS_DST_COLOR; + t->customblendfunc[1] = GL_ONE; + break; + default: + break; + } return t; } -msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex) +msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchwithprevioussurface) { msurface_t *surf; - // check if the proposed surface matches the last one we created - if (mod->num_surfaces == 0 || mod->data_surfaces[mod->num_surfaces - 1].texture != tex) + // batch if possible; primarily useful for UI rendering where bounding boxes don't matter + if (batchwithprevioussurface && mod->num_surfaces > 0 && mod->data_surfaces[mod->num_surfaces - 1].texture == tex) + return mod->data_surfaces + mod->num_surfaces - 1; + // create new surface + if (mod->max_surfaces == mod->num_surfaces) { - if (mod->max_surfaces == mod->num_surfaces) - { - mod->max_surfaces = 2 * max(mod->num_surfaces, 64); - mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces)); - mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces)); - } - surf = mod->data_surfaces + mod->num_surfaces; - mod->num_surfaces++; - memset(surf, 0, sizeof(*surf)); - surf->texture = tex; - surf->num_firsttriangle = mod->surfmesh.num_triangles; - surf->num_firstvertex = mod->surfmesh.num_vertices; - if (tex->basematerialflags & (MATERIALFLAG_SKY)) - mod->DrawSky = R_Q1BSP_DrawSky; - if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) - mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; - return surf; + mod->max_surfaces = 2 * max(mod->num_surfaces, 64); + mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces)); + mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces)); } - return mod->data_surfaces + mod->num_surfaces - 1; + surf = mod->data_surfaces + mod->num_surfaces; + mod->num_surfaces++; + memset(surf, 0, sizeof(*surf)); + surf->texture = tex; + surf->num_firsttriangle = mod->surfmesh.num_triangles; + surf->num_firstvertex = mod->surfmesh.num_vertices; + if (tex->basematerialflags & (MATERIALFLAG_SKY)) + mod->DrawSky = R_Q1BSP_DrawSky; + if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + return surf; } int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a) diff --git a/model_shared.h b/model_shared.h index f913e4bd..0d3914ed 100644 --- a/model_shared.h +++ b/model_shared.h @@ -1183,11 +1183,13 @@ void Mod_CreateCollisionMesh(dp_model_t *mod); void Mod_FreeQ3Shaders(void); void Mod_LoadQ3Shaders(void); q3shaderinfo_t *Mod_LookupQ3Shader(const char *name); -qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags); -texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe); -texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename); +qboolean Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags); +texture_shaderpass_t *Mod_CreateShaderPass(mempool_t *mempool, skinframe_t *skinframe); +texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool, const char *modelname, q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename); /// Sets up a material to render the provided skinframe. See also R_SkinFrame_LoadInternalBGRA. -void Mod_LoadCustomMaterial(texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe); +void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe); +/// Removes all shaderpasses from material, and optionally deletes the textures in the skinframes. +void Mod_UnloadCustomMaterial(texture_t *texture, qboolean purgeskins); extern cvar_t r_mipskins; extern cvar_t r_mipnormalmaps; @@ -1265,8 +1267,8 @@ void R_Q1BSP_DrawLight(struct entity_render_s *ent, int numsurfaces, const int * void Mod_Mesh_Create(dp_model_t *mod, const char *name); void Mod_Mesh_Destroy(dp_model_t *mod); void Mod_Mesh_Reset(dp_model_t *mod); -texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name); -msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex); +texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int addmaterialflags); +msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchwithprevioussurface); int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a); void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2); void Mod_Mesh_Finalize(dp_model_t *mod); diff --git a/model_sprite.c b/model_sprite.c index 2dd74695..12819e40 100644 --- a/model_sprite.c +++ b/model_sprite.c @@ -75,7 +75,7 @@ static void Mod_SpriteSetupTexture(texture_t *texture, skinframe_t *skinframe, q else if (skinframe->hasalpha) texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; texture->currentmaterialflags = texture->basematerialflags; - texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe); + texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(loadmodel->mempool, skinframe); texture->currentskinframe = skinframe; texture->surfaceflags = 0; texture->supercontents = SUPERCONTENTS_SOLID; @@ -220,7 +220,7 @@ static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i); dpsnprintf (fogname, sizeof(fogname), "%s_%ifog", loadmodel->name, i); } - if (!(skinframe = R_SkinFrame_LoadExternal(name, texflags | TEXF_COMPRESS, false))) + if (!(skinframe = R_SkinFrame_LoadExternal(name, texflags | TEXF_COMPRESS, false, false))) { unsigned char *pixels = (unsigned char *) Mem_Alloc(loadmodel->mempool, width*height*4); if (version == SPRITE32_VERSION) @@ -464,7 +464,7 @@ void Mod_IDS2_Load(dp_model_t *mod, void *buffer, void *bufferend) { const dsprite2frame_t *pinframe; pinframe = &pinqsprite->frames[i]; - if (!(skinframe = R_SkinFrame_LoadExternal(pinframe->name, texflags, false))) + if (!(skinframe = R_SkinFrame_LoadExternal(pinframe->name, texflags, false, false))) { Con_Printf("Mod_IDS2_Load: failed to load %s", pinframe->name); skinframe = R_SkinFrame_LoadMissing(); diff --git a/prvm_cmds.c b/prvm_cmds.c index e2b023e2..af6d27b9 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -3292,8 +3292,7 @@ void VM_precache_pic(prvm_prog_t *prog) flags |= CACHEPICFLAG_MIPMAP; } - // AK Draw_CachePic is supposed to always return a valid pointer - if( Draw_CachePic_Flags(s, flags)->tex == r_texture_notexture ) + if( !Draw_IsPicLoaded(Draw_CachePic_Flags(s, flags)) ) PRVM_G_INT(OFS_RETURN) = OFS_NULL; } @@ -3951,15 +3950,15 @@ void VM_getimagesize(prvm_prog_t *prog) VM_CheckEmptyString(prog, p); pic = Draw_CachePic_Flags (p, CACHEPICFLAG_NOTPERSISTENT); - if( pic->tex == r_texture_notexture ) + if (!Draw_IsPicLoaded(pic)) { PRVM_G_VECTOR(OFS_RETURN)[0] = 0; PRVM_G_VECTOR(OFS_RETURN)[1] = 0; } else { - PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width; - PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height; + PRVM_G_VECTOR(OFS_RETURN)[0] = Draw_GetPicWidth(pic); + PRVM_G_VECTOR(OFS_RETURN)[1] = Draw_GetPicHeight(pic); } PRVM_G_VECTOR(OFS_RETURN)[2] = 0; } diff --git a/r_lightning.c b/r_lightning.c index addcece8..5373e633 100644 --- a/r_lightning.c +++ b/r_lightning.c @@ -21,7 +21,7 @@ static void r_lightningbeams_start(void) static void CL_Beams_SetupExternalTexture(void) { - if (Mod_LoadTextureFromQ3Shader(&cl_beams_externaltexture, "textures/particles/lightning", false, false, TEXF_ALPHA | TEXF_FORCELINEAR)) + if (Mod_LoadTextureFromQ3Shader(r_main_mempool, "r_lightning.c", &cl_beams_externaltexture, "textures/particles/lightning", false, false, TEXF_ALPHA | TEXF_FORCELINEAR)) cl_beams_externaltexture.basematerialflags = cl_beams_externaltexture.currentmaterialflags = MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE; else Cvar_SetValueQuick(&r_lightningbeam_qmbtexture, false); @@ -77,7 +77,7 @@ static void CL_Beams_SetupBuiltinTexture(void) } skinframe = R_SkinFrame_LoadInternalBGRA("lightningbeam", TEXF_FORCELINEAR, data, texwidth, texheight, false); - Mod_LoadCustomMaterial(&cl_beams_builtintexture, "cl_beams_builtintexture", 0, MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE, skinframe); + Mod_LoadCustomMaterial(r_main_mempool, &cl_beams_builtintexture, "cl_beams_builtintexture", 0, MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE, skinframe); Mem_Free(data); } @@ -183,7 +183,7 @@ void CL_Beam_AddPolygons(const beam_t *b) // the viewer) mod = &cl_meshentitymodels[MESH_PARTICLES]; - surf = Mod_Mesh_AddSurface(mod, r_lightningbeam_qmbtexture.integer ? &cl_beams_externaltexture : &cl_beams_builtintexture); + surf = Mod_Mesh_AddSurface(mod, r_lightningbeam_qmbtexture.integer ? &cl_beams_externaltexture : &cl_beams_builtintexture, false); // polygon 1 VectorM(r_lightningbeam_thickness.value, right, offset); CL_Beam_AddQuad(mod, surf, start, end, offset, t1, t2); diff --git a/render.h b/render.h index 8f387103..3663834a 100644 --- a/render.h +++ b/render.h @@ -146,11 +146,13 @@ void R_SkinFrame_Purge(void); // set last to NULL to start from the beginning 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(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture); skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB); 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); skinframe_t *R_SkinFrame_LoadMissing(void); +skinframe_t *R_SkinFrame_LoadNoTexture(void); +skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB); rtexture_t *R_GetCubemap(const char *basename); @@ -459,7 +461,6 @@ void RSurf_SetupDepthAndCulling(void); void R_Mesh_ResizeArrays(int newvertices); texture_t *R_GetCurrentTexture(texture_t *t); -void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass); void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass); void R_AddWaterPlanes(entity_render_t *ent); void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass); diff --git a/sbar.c b/sbar.c index 14d69ce3..5028909f 100644 --- a/sbar.c +++ b/sbar.c @@ -161,7 +161,7 @@ static void sbar_start(void) for (i = 0;i < 10;i++) sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET); sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET); - sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET); + sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET | CACHEPICFLAG_FAILONMISSING); sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET); sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_bullets", CACHEPICFLAG_QUIET); @@ -219,7 +219,7 @@ static void sbar_start(void) sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET); sb_nums[1][10] = Draw_CachePic_Flags ("gfx/anum_minus", CACHEPICFLAG_QUIET); - sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET); + sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET | CACHEPICFLAG_FAILONMISSING); sb_slash = Draw_CachePic_Flags ("gfx/num_slash", CACHEPICFLAG_QUIET); sb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_shotgun", CACHEPICFLAG_QUIET); @@ -1774,7 +1774,7 @@ void Sbar_Draw (void) if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value) { pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer)); - DrawQ_Pic((vid_conwidth.integer - pic->width * crosshair_size.value) * 0.5f, (vid_conheight.integer - pic->height * crosshair_size.value) * 0.5f, pic, pic->width * crosshair_size.value, pic->height * crosshair_size.value, crosshair_color_red.value, crosshair_color_green.value, crosshair_color_blue.value, crosshair_color_alpha.value, 0); + DrawQ_Pic((vid_conwidth.integer - Draw_GetPicWidth(pic) * crosshair_size.value) * 0.5f, (vid_conheight.integer - Draw_GetPicHeight(pic) * crosshair_size.value) * 0.5f, pic, Draw_GetPicWidth(pic) * crosshair_size.value, Draw_GetPicHeight(pic) * crosshair_size.value, crosshair_color_red.value, crosshair_color_green.value, crosshair_color_blue.value, crosshair_color_alpha.value, 0); } if (cl_prydoncursor.integer > 0) @@ -1914,7 +1914,7 @@ void Sbar_DeathmatchOverlay (void) if(IS_OLDNEXUIZ_DERIVED(gamemode)) DrawQ_Pic (xmin - 8, ymin - 8, 0, xmax-xmin+1 + 2*8, ymax-ymin+1 + 2*8, 0, 0, 0, sbar_alpha_bg.value, 0); - DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); + DrawQ_Pic ((vid_conwidth.integer - Draw_GetPicWidth(sb_ranking))/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); // draw the text y = 40; @@ -2162,14 +2162,14 @@ void Sbar_Score (int margin) if (minutes >= 5) { Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0); - if(sb_colon && sb_colon->tex != r_texture_notexture) + if (Draw_IsPicLoaded(sb_colon)) DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0); Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0); } else if (minutes >= 1) { Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0); - if(sb_colon && sb_colon->tex != r_texture_notexture) + if (Draw_IsPicLoaded(sb_colon)) DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0); Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0); } @@ -2183,7 +2183,7 @@ void Sbar_Score (int margin) minutes = (int)floor(cl.time / 60); seconds = (int)(floor(cl.time) - minutes * 60); Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0); - if(sb_colon && sb_colon->tex != r_texture_notexture) + if (Draw_IsPicLoaded(sb_colon)) DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0); Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0); } @@ -2258,6 +2258,6 @@ Sbar_FinaleOverlay */ void Sbar_FinaleOverlay (void) { - DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); + DrawQ_Pic((vid_conwidth.integer - Draw_GetPicWidth(sb_finale))/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); } diff --git a/wad.c b/wad.c index 4e714b0b..fabffc3b 100644 --- a/wad.c +++ b/wad.c @@ -111,7 +111,7 @@ void W_UnloadAll(void) memset(&wad, 0, sizeof(wad)); } -unsigned char *W_GetLumpName(const char *name) +unsigned char *W_GetLumpName(const char *name, fs_offset_t *returnfilesize) { int i; fs_offset_t filesize; @@ -146,8 +146,14 @@ unsigned char *W_GetLumpName(const char *name) } for (lump = wad.gfx.lumps, i = 0;i < wad.gfx.numlumps;i++, lump++) + { if (!strcmp(clean, lump->name)) + { + if (returnfilesize) + *returnfilesize = lump->size; return (wad.gfx_base + lump->filepos); + } + } return NULL; } diff --git a/wad.h b/wad.h index 3c4297d9..ac085898 100644 --- a/wad.h +++ b/wad.h @@ -66,7 +66,7 @@ typedef struct lumpinfo_s } lumpinfo_t; void W_UnloadAll(void); -unsigned char *W_GetLumpName(const char *name); +unsigned char *W_GetLumpName(const char *name, fs_offset_t *returnfilesize); // halflife texture wads void W_LoadTextureWadFile(char *filename, int complain); -- 2.39.2