diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 182b9b41..36428fff 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -364,7 +364,7 @@ extern cvar_t worker_flush; qboolean COM_DoWork(int thread, qboolean leavelocked); #define COM_MainThreadWork() while (COM_DoWork(0, false) && worker_flush.ival) /*called each frame to do any gl uploads or whatever*/ #define COM_MainThreadFlush() while (COM_DoWork(0, false)) /*make sure the main thread has done ALL work pending*/ -typedef enum +typedef enum wgroup_e { WG_MAIN = 0, WG_LOADER = 1, diff --git a/engine/common/plugin.c b/engine/common/plugin.c index ee3dd56d..9f8db19d 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -408,6 +408,8 @@ static qboolean QDECL PlugBI_ExportInterface(const char *name, void *interfacept return R_RegisterVRDriver(currentplug, interfaceptr); if (!strcmp(name, plugimageloaderfuncs_name)) return Image_RegisterLoader(currentplug, interfaceptr); + if (!strcmp(name, plugmaterialloaderfuncs_name)) + return Material_RegisterLoader(currentplug, interfaceptr); #endif #ifdef PACKAGEMANAGER if (!strcmp(name, plugupdatesourcefuncs_name)) @@ -1536,6 +1538,7 @@ void Plug_Close(plugin_t *plug) #ifdef HAVE_CLIENT S_UnregisterSoundInputModule(plug); Image_RegisterLoader(plug, NULL); + Material_RegisterLoader(plug, NULL); #endif NET_RegisterCrypto(plug, NULL); #ifdef PACKAGEMANAGER @@ -1869,6 +1872,8 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s COM_EnumerateFiles, wildcmp, + COM_GetFileExtension, + COM_FileBase, COM_CleanUpPath, Com_BlockChecksum, FS_LoadMallocFile, @@ -2044,7 +2049,10 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s Sys_CreateMutex, Sys_LockMutex, Sys_UnlockMutex, - Sys_DestroyMutex + Sys_DestroyMutex, + + COM_AddWork, + COM_WorkerPartialSync, }; if (structsize == sizeof(funcs)) diff --git a/engine/common/sys.h b/engine/common/sys.h index 38358393..e2965de5 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -149,12 +149,16 @@ qboolean Sys_ConditionSignal(void *condv); //lock first qboolean Sys_ConditionBroadcast(void *condv); //lock first void Sys_DestroyConditional(void *condv); +enum wgroup_e; typedef struct { void *(QDECL *CreateMutex)(void); qboolean (QDECL *LockMutex)(void *mutex); qboolean (QDECL *UnlockMutex)(void *mutex); void (QDECL *DestroyMutex)(void *mutex); + + void (*AddWork)(enum wgroup_e thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b); //low priority + void (*WaitForCompletion)(void *priorityctx, int *address, int sleepwhilevalue); #define plugthreadfuncs_name "Threading" } plugthreadfuncs_t; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index d59e7926..31776fa9 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -297,6 +297,43 @@ static qboolean Shader_LocateSource(const char *name, const char **buf, size_t * static void Shader_ReadShader(parsestate_t *ps, const char *shadersource, shadercachefile_t *sourcefile); static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename); + +static struct +{ + void *module; + plugmaterialloaderfuncs_t *funcs; +} *materialloader; +static size_t materialloader_count; +qboolean Material_RegisterLoader(void *module, plugmaterialloaderfuncs_t *driver) +{ + int i; + if (!driver) + { + for (i = 0; i < materialloader_count; ) + { + if (materialloader[i].module == module) + { + memmove(&materialloader[i], &materialloader[i+1], materialloader_count-(i+1)); + materialloader_count--; + } + else + i++; + } + return true; + } + else + { + void *n = BZ_Malloc(sizeof(*materialloader)*(materialloader_count+1)); + memcpy(n, materialloader, sizeof(*materialloader)*materialloader_count); + Z_Free(materialloader); + materialloader = n; + materialloader[materialloader_count].module = module; + materialloader[materialloader_count].funcs = driver; + materialloader_count++; + return true; + } +} + //=========================================================================== static qboolean Shader_EvaluateCondition(shader_t *shader, const char **ptr) @@ -2048,13 +2085,7 @@ typedef struct sgeneric_s qboolean failed; } sgeneric_t; static sgeneric_t *sgenerics; -struct sbuiltin_s -{ - int qrtype; - int apiver; - char name[MAX_QPATH]; - char *body; -} sbuiltins[] = +static struct sbuiltin_s sbuiltins[] = { #include "r_bishaders.h" {QR_NONE} @@ -2155,23 +2186,35 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) else { int ver; - for (i = 0; *sbuiltins[i].name; i++) + const struct sbuiltin_s *progs; + unsigned int l; + for (l = 0; l <= materialloader_count; l++) { - if (sbuiltins[i].qrtype == qrtype && !strcmp(sbuiltins[i].name, basicname)) - { - ver = sbuiltins[i].apiver; + if (l == materialloader_count) + progs = sbuiltins; + else if (materialloader[l].funcs && materialloader[l].funcs->builtinshaders) + progs = materialloader[l].funcs->builtinshaders; + else + continue; - if (ver < sh_config.minver || ver > sh_config.maxver) - if (!(qrenderer==QR_OPENGL&&ver==110)) + for (i = 0; *progs[i].name; i++) + { + if (progs[i].qrtype == qrtype && !strcmp(progs[i].name, basicname)) + { + ver = progs[i].apiver; + + if (ver < sh_config.minver || ver > sh_config.maxver) + if (!(qrenderer==QR_OPENGL&&ver==110)) + continue; + + TRACE(("Loading Embedded %s\n", g->name)); + g->failed = !Shader_LoadPermutations(g->name, &g->prog, progs[i].body, qrtype, ver, blobname); + + if (g->failed) continue; - TRACE(("Loading Embedded %s\n", g->name)); - g->failed = !Shader_LoadPermutations(g->name, &g->prog, sbuiltins[i].body, qrtype, ver, blobname); - - if (g->failed) - continue; - - return; + return; + } } } TRACE(("Program unloadable %s\n", g->name)); @@ -2489,6 +2532,17 @@ static void Shader_HLSL11ProgramName (parsestate_t *ps, const char **ptr) Shader_SLProgramName(shader,pass,ptr,QR_DIRECT3D11); } +static void Shaderpass_BlendFunc (parsestate_t *ps, const char **ptr); +static void Shader_ProgBlendFunc (parsestate_t *ps, const char **ptr) +{ + if (ps->s->prog) + { + ps->pass = ps->s->passes; + Shaderpass_BlendFunc(ps, ptr); + ps->pass = NULL; + } +} + static void Shader_ReflectCube(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); @@ -2847,7 +2901,7 @@ static shaderkey_t shaderkeys[] = {"glslprogram", Shader_GLSLProgramName, "fte"}, //for renderers that accept embedded glsl {"hlslprogram", Shader_HLSL9ProgramName, "fte"}, //for d3d with embedded hlsl {"hlsl11program", Shader_HLSL11ProgramName, "fte"}, //for d3d with embedded hlsl -// {"progblendfunc", Shader_ProgBlendFunc, "fte"}, //specifies the blend mode (actually just overrides the first subpasses' blendmode. + {"progblendfunc", Shader_ProgBlendFunc, "fte"}, //specifies the blend mode (actually just overrides the first subpasses' blendmode. // {"progmap", Shader_ProgMap, "fte"}, //avoids needing extra subpasses (actually just inserts an extra pass). //dp compat @@ -4353,8 +4407,9 @@ static const char *Shader_Skip(const char *file, const char *shadername, const c return ptr; } -static void Shader_Reset(shader_t *s) +static void Shader_Reset(parsestate_t *ps) { + shader_t *s = ps->s; extern cvar_t r_refractreflect_scale; char name[MAX_QPATH]; int id = s->id; @@ -4393,7 +4448,7 @@ static void Shader_Reset(shader_t *s) static void Shader_Regenerate(parsestate_t *ps, const char *shortname) { - Shader_Reset(ps->s); + Shader_Reset(ps); if (!strcmp(shortname, "textures/common/clip") || !strcmp(shortname, "textures/common/nodraw") || !strcmp(shortname, "common/nodraw")) Shader_DefaultScript(ps, shortname, @@ -7279,6 +7334,12 @@ static void Shader_ReadShader(parsestate_t *ps, const char *shadersource, shader } } +static void Shader_LoadMaterialString(parsestate_t *ps, const char *shadertext) +{ //callback for our external material loaders. + Shader_Reset(ps); + Shader_ReadShader(ps, shadertext, NULL); +} + static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename) { size_t offset = 0, length; @@ -7294,8 +7355,15 @@ static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename) if (!strcmp(token, ".mat") || !*token) { char shaderfile[MAX_QPATH]; + size_t i; if (!*token) { + for (i = 0; i < materialloader_count; i++) + { + if (materialloader[i].funcs->ReadMaterial(ps, parsename, Shader_LoadMaterialString)) + return true; + } + Q_snprintfz(shaderfile, sizeof(shaderfile), "%s.mat", parsename); file = COM_LoadTempMoreFile(shaderfile, &length); } @@ -7303,7 +7371,7 @@ static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename) file = COM_LoadTempMoreFile(parsename, &length); if (file) { - Shader_Reset(ps->s); + Shader_Reset(ps); token = COM_ParseExt (&file, true, false); //we need to skip over the leading {. if (*token != '{') token = COM_ParseExt (&file, true, false); //try again, in case we found some legacy name. @@ -7331,7 +7399,7 @@ static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename) return false; } - Shader_Reset(ps->s); + Shader_Reset(ps); Shader_ReadShader(ps, file, sourcefile); diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 8756864c..252ec7f5 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -710,6 +710,24 @@ struct shader_s */ }; +struct shaderparsestate_s; +struct sbuiltin_s +{ + int qrtype; + int apiver; + char name[MAX_QPATH]; + char *body; +}; +typedef struct +{ + const char *loadername; + qboolean (*ReadMaterial)(struct shaderparsestate_s *ps, const char *filename, void (*LoadMaterialString)(struct shaderparsestate_s *ps, const char *script)); + + struct sbuiltin_s *builtinshaders; +#define plugmaterialloaderfuncs_name "MaterialLoader" +} plugmaterialloaderfuncs_t; +qboolean Material_RegisterLoader(void *module, plugmaterialloaderfuncs_t *loader); + extern unsigned int r_numshaders; extern unsigned int r_maxshaders; extern shader_t **r_shaders; diff --git a/engine/shaders/generatebuiltinsl.c b/engine/shaders/generatebuiltinsl.c index b24e495b..a3d0417b 100644 --- a/engine/shaders/generatebuiltinsl.c +++ b/engine/shaders/generatebuiltinsl.c @@ -109,7 +109,7 @@ void dumpprogblob(FILE *out, FILE *src) fprintf(out, "\""); } -struct shadertype_s +static struct shadertype_s { char *abrv; char *filepattern; @@ -126,12 +126,48 @@ struct shadertype_s }; //tbh we should precompile the d3d shaders. -int main(void) +static void dumpprogram(FILE *c, const char *progname) +{ + FILE *s; + char line[1024]; + int a; + printf("%25s: ", progname); + for (a = 0; a < sizeof(shadertype)/sizeof(shadertype[0]); a++) + { + sprintf(line, shadertype[a].filepattern, progname); + if (shadertype[a].apiversion == -1) + s = fopen(line, "rb"); + else + s = fopen(line, "rt"); + if (!s) + { + printf("%4s", ""); + continue; + } + fprintf(c, "#ifdef %s\n", shadertype[a].preprocessor); + fprintf(c, "{%s, %i, \"%s\",\n", shadertype[a].rendererapi, shadertype[a].apiversion, progname); + if (shadertype[a].apiversion == -1) + dumpprogblob(c,s); + else + dumpprogstring(c, s); + fputs("},\n", c); + fprintf(c, "#endif\n"); + fclose(s); + fflush(c); + + printf("%4s", shadertype[a].abrv); + } + printf("\n"); +} + +int main(int argc, const char **argv) { FILE *c, *s; - char line[1024]; int i, j, a; - c = fopen("../gl/r_bishaders.h", "wt"); + + const char *outname = ((argc>1)?argv[1]:"../gl/r_bishaders.h"); + + c = fopen(outname, "wt"); if (!c) { @@ -141,35 +177,15 @@ int main(void) fprintf(c, "/*\nWARNING: THIS FILE IS GENERATED BY '"__FILE__"'.\nYOU SHOULD NOT EDIT THIS FILE BY HAND\n*/\n\n"); - for (i = 0; *shaders[i]; i++) - { - printf("%25s: ", shaders[i]); - for (a = 0; a < sizeof(shadertype)/sizeof(shadertype[0]); a++) - { - sprintf(line, shadertype[a].filepattern, shaders[i]); - if (shadertype[a].apiversion == -1) - s = fopen(line, "rb"); - else - s = fopen(line, "rt"); - if (!s) - { - printf("%4s", ""); - continue; - } - fprintf(c, "#ifdef %s\n", shadertype[a].preprocessor); - fprintf(c, "{%s, %i, \"%s\",\n", shadertype[a].rendererapi, shadertype[a].apiversion, shaders[i]); - if (shadertype[a].apiversion == -1) - dumpprogblob(c,s); - else - dumpprogstring(c, s); - fputs("},\n", c); - fprintf(c, "#endif\n"); - fclose(s); - fflush(c); - - printf("%4s", shadertype[a].abrv); - } - printf("\n"); + if (argc>2) + { //if we're passed a file list on the commandline then just use that (generally for plugins). + for (i = 2; i < argc; i++) + dumpprogram(c, argv[i]); + } + else + { //use our built in list. + for (i = 0; *shaders[i]; i++) + dumpprogram(c, shaders[i]); } fclose(c); diff --git a/plugins/plugin.h b/plugins/plugin.h index 397e65d3..7e63d174 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -349,6 +349,8 @@ typedef struct //for plugins that need to read/write files... //helpers F(int, WildCmp, (const char *wild, const char *string)); + F(const char *,GetExtension,(const char *filename, const char *ignoreext)); + F(void, FileBase, (const char *in, char *out, int outlen)); F(void, CleanUpPath, (char *str)); F(unsigned int,BlockChecksum,(const void *buffer, int length)); //mostly for pack hashes. F(qbyte*, LoadFile, (const char *fname, size_t *fsize)); //plugfuncs->Free