From ab2dc14f499824e16b273f283ab4a840b4a31ffe Mon Sep 17 00:00:00 2001 From: Spoike Date: Wed, 3 Nov 2021 20:31:21 +0000 Subject: [PATCH] Add support for image-loading plugins. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6103 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/image.c | 104 ++++++++++++++++++++++++++++++++++++++++- engine/client/render.h | 10 ++++ engine/common/plugin.c | 19 ++++++++ plugins/plugin.h | 16 +++++++ 4 files changed, 148 insertions(+), 1 deletion(-) diff --git a/engine/client/image.c b/engine/client/image.c index a9862c25c..5586aacb7 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -230,6 +230,44 @@ static float HalfToFloat(unsigned short val); static unsigned short FloatToHalf(float val); + +static struct +{ + void *module; + plugimageloaderfuncs_t *funcs; +} *imageloader; +static size_t imageloader_count; +qboolean Image_RegisterLoader(void *module, plugimageloaderfuncs_t *driver) +{ + int i; + if (!driver) + { + for (i = 0; i < imageloader_count; ) + { + if (imageloader[i].module == module) + { + memmove(&imageloader[i], &imageloader[i+1], imageloader_count-(i+1)); + imageloader_count--; + } + else + i++; + } + return true; + } + else + { + void *n = BZ_Malloc(sizeof(*imageloader)*(imageloader_count+1)); + memcpy(n, imageloader, sizeof(*imageloader)*imageloader_count); + Z_Free(imageloader); + imageloader = n; + imageloader[imageloader_count].module = module; + imageloader[imageloader_count].funcs = driver; + imageloader_count++; + return true; + } +} + + #if defined(AVAIL_JPEGLIB) || defined(AVAIL_PNGLIB) static void GenerateXMPData(char *blob, size_t blobsize, int width, int height, unsigned int metainfo) { //XMP is a general thing that applies to multiple formats - or at least png+jpeg. @@ -7251,6 +7289,7 @@ void Image_PrintInputFormatVersions(void) //if force_rgba8 then it guarentees rgba8 or rgbx8, otherwise can return l8, etc qbyte *ReadRawImageFile(qbyte *buf, int len, int *width, int *height, uploadfmt_t *format, qboolean force_rgba8, const char *fname) { + size_t l, i; qbyte *data; *format = PTI_RGBX8; #ifdef IMAGEFMT_TGA @@ -7344,6 +7383,58 @@ qbyte *ReadRawImageFile(qbyte *buf, int len, int *width, int *height, uploadfmt_ } #endif + for (l = 0; l < imageloader_count; l++) + { + struct pendingtextureinfo *mips = imageloader[l].funcs->ReadImageFile(0, fname, buf, len); + if (mips) + { + if (mips->extrafree != buf) + Sys_Error("Image loader did weird extrafree things."); + mips->extrafree = NULL; + + //free any excess mips + while (mips->mipcount > 1) + if (mips->mip[--mips->mipcount].needfree) + BZ_Free(mips->mip[mips->mipcount].data); + + if (mips->mipcount > 0 && mips->type == PTI_2D) + { + if (force_rgba8) + { + qboolean rgbx8only[PTI_MAX] = {0}; + rgbx8only[PTI_RGBX8] = true; + rgbx8only[PTI_RGBA8] = true; + Image_ChangeFormat(mips, rgbx8only, mips->encoding, fname); + } + + if (mips->mip[0].needfree) + { + data = mips->mip[0].data; + mips->mip[0].data = NULL; + mips->mip[0].needfree = false; + } + else + { + data = BZ_Malloc(mips->mip[0].datasize); + memcpy(data, mips->mip[0].data, mips->mip[0].datasize); + } + *width = mips->mip[0].width; + *height = mips->mip[0].height; + *format = mips->encoding; + } + for (i = 0; i < mips->mipcount; i++) + if (mips->mip[i].needfree) + BZ_Free(mips->mip[i].data); + + if (mips->extrafree && mips->extrafree) + BZ_Free(mips->extrafree); + BZ_Free(mips); + + if (data) + return data; + } + } + #ifdef IMAGEFMT_LMP if (len >= 8) //.lmp has no magic id. guess at it. { @@ -13154,6 +13245,7 @@ struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname qbyte *rgbadata; int imgwidth, imgheight; + size_t l; struct pendingtextureinfo *mips = NULL; @@ -13174,6 +13266,8 @@ struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname if (!mips && filedata[0] == 'B' && filedata[1] == 'L' && filedata[2] == 'P' && filedata[3] == '2') mips = Image_ReadBLPFile(flags, fname, filedata, filesize); #endif + for (l = 0; !mips && l < imageloader_count; l++) + mips = imageloader[l].funcs->ReadImageFile(flags, fname, filedata, filesize); #ifdef IMAGEFMT_ASTC if (!mips && filesize>= 16 && filedata[0] == 0x13 && filedata[1] == 0xab && filedata[2] == 0xa1 && filedata[3] == 0x5c) mips = Image_ReadASTCFile(flags, fname, filedata, filesize); @@ -13692,6 +13786,8 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be continue; s = COM_SkipPath(nicename); + if (!*s) + continue; n = basename; while (*s && (*s != '.'||exactext) && n < basename+sizeof(basename)-5) *n++ = *s++; @@ -13837,7 +13933,7 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t unsigned int locflags = 0; vfsfile_t *f; - size_t fsize; + size_t fsize, l; char *buf; int i, j; @@ -13919,6 +14015,12 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t if (!mips) mips = Image_ReadDDSFile(tex->flags, altname, buf, fsize); #endif + for (l = 0; !mips && l < imageloader_count; l++) + { + if (!imageloader[l].funcs->canloadcubemaps) + continue; + mips = imageloader[l].funcs->ReadImageFile(tex->flags, altname, buf, fsize); + } if (!mips) BZ_Free(buf); } diff --git a/engine/client/render.h b/engine/client/render.h index 7b55e6a46..f7c59cc0a 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -500,6 +500,16 @@ void Image_ChangeFormat(struct pendingtextureinfo *mips, qboolean *allowedformat void Image_Premultiply(struct pendingtextureinfo *mips); void *Image_FlipImage(const void *inbuffer, void *outbuffer, int *inoutwidth, int *inoutheight, int pixelbytes, qboolean flipx, qboolean flipy, qboolean flipd); +typedef struct +{ + const char *loadername; + size_t pendingtextureinfosize; + qboolean canloadcubemaps; + struct pendingtextureinfo *(*ReadImageFile)(unsigned int imgflags, const char *fname, qbyte *filedata, size_t filesize); +#define plugimageloaderfuncs_name "ImageLoader" +} plugimageloaderfuncs_t; +qboolean Image_RegisterLoader(void *module, plugimageloaderfuncs_t *loader); + #ifdef D3D8QUAKE void D3D8_Set2D (void); void D3D8_UpdateFiltering (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis); diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 46037575e..7868a2e6f 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -406,6 +406,8 @@ static qboolean QDECL PlugBI_ExportInterface(const char *name, void *interfacept #ifdef HAVE_CLIENT if (!strcmp(name, plugvrfuncs_name)) return R_RegisterVRDriver(currentplug, interfaceptr); + if (!strcmp(name, plugimageloaderfuncs_name)) + return Image_RegisterLoader(currentplug, interfaceptr); #endif #ifdef PACKAGEMANAGER if (!strcmp(name, plugupdatesourcefuncs_name)) @@ -1533,6 +1535,7 @@ void Plug_Close(plugin_t *plug) #endif #ifdef HAVE_CLIENT S_UnregisterSoundInputModule(plug); + Image_RegisterLoader(plug, NULL); #endif NET_RegisterCrypto(plug, NULL); #ifdef PACKAGEMANAGER @@ -1783,6 +1786,12 @@ plugcorefuncs_t plugcorefuncs = Sys_LoadLibrary, Sys_GetAddressForName, Sys_CloseLibrary, + + Z_Malloc, + BZ_Realloc, + Z_Free, + ZG_Malloc, + ZG_FreeGroup, }; static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t structsize) @@ -1989,6 +1998,16 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s if (structsize == sizeof(funcs)) return &funcs; } + if (!strcmp(interfacename, plugimagefuncs_name)) + { + static plugimagefuncs_t funcs = + { + Image_BlockSizeForEncoding, + Image_FormatName, + }; + if (structsize == sizeof(funcs)) + return &funcs; + } #endif #ifdef SUPPORT_ICE diff --git a/plugins/plugin.h b/plugins/plugin.h index 2de5aca7e..24a01bdb7 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -197,6 +197,15 @@ typedef struct //core stuff F(dllhandle_t*,LoadDLL, (const char *modulename, struct dllfunction_s *funcs)); F(void*, GetDLLSymbol, (dllhandle_t *handle, const char *symbolname)); F(void, CloseDLL, (dllhandle_t *handle)); //not guarenteed to actually do anything, of course. + + //general memory (mallocs and frees over dll boundaries is not usable on windows) + F(void*, Malloc, (size_t size)); + F(void*, Realloc, (void *memptr, size_t size)); //doesn't zero-fill, so faster (when memptr is NULL). + F(void, Free, (void *memptr)); + + //for lazy mallocs + F(void*, GMalloc, (struct zonegroup_s *ctx, size_t size)); + F(void, GFreeAll, (struct zonegroup_s *ctx)); #define plugcorefuncs_name "Core" } plugcorefuncs_t; @@ -254,6 +263,13 @@ typedef struct #define plugaudiofuncs_name "Audio" } plugaudiofuncs_t; +typedef struct +{ + F(void, BlockSizeForEncoding,(uploadfmt_t encoding, unsigned int *blockbytes, unsigned int *blockwidth, unsigned int *blockheight, unsigned int *blockdepth)); + F(const char *,FormatName, (uploadfmt_t encoding)); +#define plugimagefuncs_name "Image" +} plugimagefuncs_t; + typedef struct //q1 client/network info { F(int, GetStats, (int seat, unsigned int *stats, int maxstats));