From 4cb11861e4e0a2d63eed1277e565ed38868a7ed8 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Sun, 3 Nov 2024 02:58:31 +0300 Subject: [PATCH] engine: client: reimplement Mod_LoadMapSprite on engine side --- engine/client/cl_game.c | 122 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 52ebf7db..d73cddb8 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -1165,6 +1165,126 @@ void CL_ClearSpriteTextures( void ) clgame.sprites[i].needload = NL_UNREFERENCED; } +// it's a Valve default value for LoadMapSprite (probably must be power of two) +#define MAPSPRITE_SIZE 128 + +/* +==================== +Mod_LoadMapSprite + +Loading a bitmap image as sprite with multiple frames +as pieces of input image +==================== +*/ +static void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean *loaded ) +{ + rgbdata_t *pix, temp = { 0 }; + char texname[128]; + int i, w, h; + int xl, yl; + int numframes; + msprite_t *psprite; + char poolname[MAX_VA_STRING]; + + if( loaded ) *loaded = false; + Q_snprintf( texname, sizeof( texname ), "#%s", mod->name ); + Image_SetForceFlags( IL_OVERVIEW ); + pix = FS_LoadImage( texname, buffer, size ); + Image_ClearForceFlags(); + if( !pix ) return; // bad image or something else + + mod->type = mod_sprite; + + if( pix->width % MAPSPRITE_SIZE ) + w = pix->width - ( pix->width % MAPSPRITE_SIZE ); + else w = pix->width; + + if( pix->height % MAPSPRITE_SIZE ) + h = pix->height - ( pix->height % MAPSPRITE_SIZE ); + else h = pix->height; + + if( w < MAPSPRITE_SIZE ) w = MAPSPRITE_SIZE; + if( h < MAPSPRITE_SIZE ) h = MAPSPRITE_SIZE; + + // resample image if needed + Image_Process( &pix, w, h, IMAGE_FORCE_RGBA|IMAGE_RESAMPLE, 0.0f ); + + w = h = MAPSPRITE_SIZE; + + // check range + if( w > pix->width ) w = pix->width; + if( h > pix->height ) h = pix->height; + + // determine how many frames we needs + numframes = (pix->width * pix->height) / (w * h); + Q_snprintf( poolname, sizeof( poolname ), "^2%s^7", mod->name ); + mod->mempool = Mem_AllocPool( poolname ); + psprite = Mem_Calloc( mod->mempool, sizeof( msprite_t ) + ( numframes - 1 ) * sizeof( psprite->frames )); + mod->cache.data = psprite; // make link to extradata + + psprite->type = SPR_FWD_PARALLEL_ORIENTED; + psprite->texFormat = SPR_ALPHTEST; + psprite->numframes = mod->numframes = numframes; + psprite->radius = sqrt(((w >> 1) * (w >> 1)) + ((h >> 1) * (h >> 1))); + + mod->mins[0] = mod->mins[1] = -w / 2; + mod->maxs[0] = mod->maxs[1] = w / 2; + mod->mins[2] = -h / 2; + mod->maxs[2] = h / 2; + + // create a temporary pic + temp.width = w; + temp.height = h; + temp.type = pix->type; + temp.flags = pix->flags; + temp.size = w * h * PFDesc[temp.type].bpp; + temp.buffer = Mem_Malloc( mod->mempool, temp.size ); + temp.palette = NULL; + + // chop the image and upload into video memory + for( i = xl = yl = 0; i < numframes; i++ ) + { + mspriteframe_t *pspriteframe; + int xh = xl + w, yh = yl + h, x, y, j; + int linedelta = ( pix->width - w ) * 4; + byte *src = pix->buffer + ( yl * pix->width + xl ) * 4; + byte *dst = temp.buffer; + + // cut block from source + for( y = yl; y < yh; y++ ) + { + for( x = xl; x < xh; x++ ) + for( j = 0; j < 4; j++ ) + *dst++ = *src++; + src += linedelta; + } + + // build uinque frame name + Q_snprintf( texname, sizeof( texname ), "#MAP/%s_%i%i.spr", mod->name, i / 10, i % 10 ); + + psprite->frames[i].frameptr = Mem_Calloc( mod->mempool, sizeof( mspriteframe_t )); + pspriteframe = psprite->frames[i].frameptr; + pspriteframe->width = w; + pspriteframe->height = h; + pspriteframe->up = ( h >> 1 ); + pspriteframe->left = -( w >> 1 ); + pspriteframe->down = ( h >> 1 ) - h; + pspriteframe->right = w + -( w >> 1 ); + pspriteframe->gl_texturenum = GL_LoadTextureInternal( texname, &temp, TF_IMAGE ); + + xl += w; + if( xl >= pix->width ) + { + xl = 0; + yl += h; + } + } + + FS_FreeImage( pix ); + Mem_Free( temp.buffer ); + if( loaded ) *loaded = true; +} + /* ============= CL_LoadHudSprite @@ -1210,7 +1330,7 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite, return false; if( type == SPR_MAPSPRITE ) - ref.dllFuncs.Mod_LoadMapSprite( m_pSprite, buf, size, &loaded ); + Mod_LoadMapSprite( m_pSprite, buf, size, &loaded ); else { Mod_LoadSpriteModel( m_pSprite, buf, &loaded );