268f122b23
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6121 fc73d0e0-1445-4013-8a0c-d673dee63da5
551 lines
No EOL
19 KiB
C
551 lines
No EOL
19 KiB
C
#include "../plugin.h"
|
|
#include "shader.h"
|
|
static plugfsfuncs_t *fsfuncs;
|
|
|
|
typedef struct shaderparsestate_s parsestate_t;
|
|
|
|
typedef struct
|
|
{
|
|
char **savefile;
|
|
char *sourcefile;
|
|
char type[MAX_QPATH];
|
|
char normalmap[MAX_QPATH];
|
|
struct
|
|
{
|
|
char name[MAX_QPATH];
|
|
} tex[5];
|
|
char envmap[MAX_QPATH];
|
|
char envmapmask[MAX_QPATH];
|
|
char envfrombase;
|
|
char halflambert;
|
|
|
|
float alphatestref;
|
|
char *blendfunc;
|
|
qboolean alphatest;
|
|
qboolean culldisable;
|
|
qboolean ignorez;
|
|
char *replaceblock;
|
|
} vmtstate_t;
|
|
|
|
|
|
static void VARGS Q_strlcatfz (char *dest, size_t *offset, size_t size, const char *fmt, ...) LIKEPRINTF(4);
|
|
static void VARGS Q_strlcatfz (char *dest, size_t *offset, size_t size, const char *fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
|
|
dest += *offset;
|
|
size -= *offset;
|
|
|
|
va_start (argptr, fmt);
|
|
Q_vsnprintfz(dest, size, fmt, argptr);
|
|
va_end (argptr);
|
|
*offset += strlen(dest);
|
|
}
|
|
static void Q_StrCat(char **ptr, const char *append)
|
|
{
|
|
size_t oldlen = *ptr?strlen(*ptr):0;
|
|
size_t newlen = strlen(append);
|
|
char *newptr = plugfuncs->Malloc(oldlen+newlen+1);
|
|
memcpy(newptr, *ptr, oldlen);
|
|
memcpy(newptr+oldlen, append, newlen);
|
|
newptr[oldlen+newlen] = 0;
|
|
plugfuncs->Free(*ptr);
|
|
*ptr = newptr;
|
|
}
|
|
|
|
//case comparisons are specific to ascii only, so this should be 'safe' for utf-8 strings too.
|
|
int Q_strncasecmp (const char *s1, const char *s2, int n)
|
|
{
|
|
int c1, c2;
|
|
|
|
while (1)
|
|
{
|
|
c1 = *s1++;
|
|
c2 = *s2++;
|
|
|
|
if (!n--)
|
|
return 0; // strings are equal until end point
|
|
|
|
if (c1 != c2)
|
|
{
|
|
if (c1 >= 'a' && c1 <= 'z')
|
|
c1 -= ('a' - 'A');
|
|
if (c2 >= 'a' && c2 <= 'z')
|
|
c2 -= ('a' - 'A');
|
|
if (c1 != c2)
|
|
{ // strings not equal
|
|
if (c1 > c2)
|
|
return 1; // strings not equal
|
|
return -1;
|
|
}
|
|
}
|
|
if (!c1)
|
|
return 0; // strings are equal
|
|
// s1++;
|
|
// s2++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
int Q_strcasecmp (const char *s1, const char *s2)
|
|
{
|
|
return Q_strncasecmp (s1, s2, 0x7fffffff);
|
|
}
|
|
|
|
static qboolean VMT_ReadVMT(const char *materialname, vmtstate_t *st); //this is made more complicated on account of includes allowing recursion
|
|
static char *VMT_ParseBlock(const char *fname, vmtstate_t *st, char *line)
|
|
{ //assumes the open { was already parsed, but will parse the close.
|
|
char *replace = NULL;
|
|
com_tokentype_t ttype;
|
|
char key[MAX_OSPATH];
|
|
char value[MAX_OSPATH];
|
|
char *qmark;
|
|
qboolean cond;
|
|
for(;line;)
|
|
{
|
|
line = cmdfuncs->ParseToken(line, key, sizeof(key), &ttype);
|
|
if (ttype == TTP_RAWTOKEN && !strcmp(key, "}"))
|
|
break; //end-of-block
|
|
line = cmdfuncs->ParseToken(line, value, sizeof(value), &ttype);
|
|
if (ttype == TTP_RAWTOKEN && !strcmp(value, "{"))
|
|
{ //sub block. we don't go into details here.
|
|
if (!Q_strcasecmp(key, "replace"))
|
|
replace = line;
|
|
else
|
|
Con_DPrintf("%s: Unknown block \"%s\"\n", fname, key);
|
|
line = VMT_ParseBlock(fname, NULL, line);
|
|
continue;
|
|
}
|
|
|
|
while ((qmark = strchr(key, '?')))
|
|
{
|
|
*qmark++ = 0;
|
|
if (!Q_strcasecmp(key, "srgb"))
|
|
cond = false;//!!(vid.flags & VID_SRGBAWARE);
|
|
else
|
|
{
|
|
Con_DPrintf("%s: Unknown vmt conditional \"%s\"\n", fname, key);
|
|
cond = false;
|
|
}
|
|
if (!cond)
|
|
{
|
|
*key = 0;
|
|
break;
|
|
}
|
|
else
|
|
memmove(key, qmark, strlen(qmark)+1);
|
|
}
|
|
|
|
if (!*key || !st)
|
|
;
|
|
else if (!Q_strcasecmp(key, "include"))
|
|
{
|
|
if (!VMT_ReadVMT(value, st))
|
|
return NULL;
|
|
}
|
|
else if (!Q_strcasecmp(key, "$basetexture") || !Q_strcasecmp(key, "$hdrbasetexture")) //fixme: hdr version should probably override the other. order matters.
|
|
Q_strlcpy(st->tex[0].name, value, sizeof(st->tex[0].name));
|
|
else if (!Q_strcasecmp(key, "$hdrcompressedtexture")) //named texture is R8G8B8E8 and needs to be decompressed manually... should probably just use e5bgr9 but we don't have a way to transcode it here.
|
|
;
|
|
else if (!Q_strcasecmp(key, "$basetexturetransform"))
|
|
;
|
|
else if (!Q_strcasecmp(key, "$bumpmap")) // same as normalmap ~eukara
|
|
{
|
|
Q_strlcpy(st->normalmap, value, sizeof(st->normalmap));
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
}
|
|
else if (!Q_strcasecmp(key, "$ssbump"))
|
|
;
|
|
else if (!Q_strcasecmp(key, "$ssbumpmathfix"))
|
|
;
|
|
else if (!Q_strcasecmp(key, "$basetexture2") || !strcmp(key, "$texture2"))
|
|
Q_strlcpy(st->tex[1].name, value, sizeof(st->tex[1].name));
|
|
else if (!Q_strcasecmp(key, "$basetexturetransform2"))
|
|
;
|
|
else if (!Q_strcasecmp(key, "$surfaceprop"))
|
|
;
|
|
|
|
else if (!Q_strcasecmp(key, "$ignorez"))
|
|
st->ignorez = !!atoi(value);
|
|
else if (!Q_strcasecmp(key, "$nocull") && (!strcmp(value, "1")||!strcmp(value, "0")))
|
|
st->culldisable = atoi(value);
|
|
else if (!Q_strcasecmp(key, "$alphatest") && (!strcmp(value, "1")||!strcmp(value, "0")))
|
|
st->alphatest = atoi(value);
|
|
else if (!Q_strcasecmp(key, "$alphatestreference"))
|
|
st->alphatestref = atof(value);
|
|
else if (!Q_strcasecmp(key, "$alphafunc"))
|
|
{
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
}
|
|
else if (!Q_strcasecmp(key, "$alpha"))
|
|
{
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
}
|
|
else if (!Q_strcasecmp(key, "$translucent"))
|
|
{
|
|
if (atoi(value))
|
|
st->blendfunc = "src_alpha one_minus_src_alpha\n";
|
|
}
|
|
else if (!Q_strcasecmp(key, "$additive"))
|
|
{
|
|
if (atoi(value))
|
|
st->blendfunc = "src_one one_minus_src_alpha\n";
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
}
|
|
else if (!Q_strcasecmp(key, "$halflambert"))
|
|
st->halflambert = 1;
|
|
else if (!Q_strcasecmp(key, "$color"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$vertexcolor"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$vertexalpha"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$decal"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$decalscale"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$decalsize"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$envmap"))
|
|
Q_strlcpy(st->envmap, value, sizeof(st->envmap));
|
|
else if (!Q_strcasecmp(key, "$envmapmask"))
|
|
Q_strlcpy(st->envmapmask, value, sizeof(st->envmapmask));
|
|
else if (!Q_strcasecmp(key, "$envmapcontrast"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$envmaptint"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$envmapsaturation"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$basealphaenvmapmask"))
|
|
st->envfrombase=1;
|
|
else if (!Q_strcasecmp(key, "$normalmapalphaenvmapmask"))
|
|
st->envfrombase=0;
|
|
else if (!Q_strcasecmp(key, "$crackmaterial"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$selfillum"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$selfillummask"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$selfillumtint"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$nofog"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$nomip"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$nodecal"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$detail"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$detailscale"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$detailtint"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$detailblendfactor"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$detailblendmode"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
|
|
else if (!Q_strcasecmp(key, "$surfaceprop2"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$AllowAlphaToCoverage"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$blendmodulatetexture"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
|
|
//water/reflection stuff
|
|
else if (!Q_strcasecmp(key, "$refracttinttexture"))
|
|
Q_strlcpy(st->tex[0].name, value, sizeof(st->tex[0].name));
|
|
else if (!Q_strcasecmp(key, "$refracttexture"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$refractamount"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$refracttint"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$reflecttexture"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$reflectamount"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$reflecttint"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$fresnelpower"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$minreflectivity"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$maxreflectivity"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$normalmap"))
|
|
{
|
|
Q_strlcpy(st->normalmap, value, sizeof(st->normalmap));
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
}
|
|
else if (!Q_strcasecmp(key, "$bumpframe"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$fogenable"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$fogcolor"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$fogstart"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$fogend"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$abovewater"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$underwateroverlay"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$reflectentities"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$scale"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$bottommaterial"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$scroll1"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
else if (!Q_strcasecmp(key, "$scroll2"))
|
|
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
|
|
|
|
else if (*key == '%')
|
|
; //editor lines
|
|
else
|
|
Con_DPrintf("%s: Unknown field \"%s\"\n", fname, key);
|
|
}
|
|
if (replace)
|
|
VMT_ParseBlock(fname, st, replace);
|
|
return line;
|
|
}
|
|
static void Shader_GenerateFromVMT(parsestate_t *ps, vmtstate_t *st, const char *shortname, void (*LoadMaterialString)(parsestate_t *ps, const char *script))
|
|
{
|
|
size_t offset = 0;
|
|
char script[8192];
|
|
char *progargs = "";
|
|
|
|
if (!*st->tex[0].name) //fill in a default...
|
|
Q_strlcpy(st->tex[0].name, shortname, sizeof(st->tex[0].name));
|
|
|
|
if (st->alphatest)
|
|
progargs = "#MASK=0.5#MASKLT"; //alphamask has to be handled by glsl (when glsl is used)
|
|
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\n");
|
|
if (!Q_strcasecmp(st->type, "WorldVertexTransition"))
|
|
{ //attempt to do terrain blending
|
|
Q_strlcpy(st->type, "vmt/transition#TWOWAY", sizeof(st->type));
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tprogram \"%s%s\"\n", st->type, progargs);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tdiffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tuppermap \"%s%s.vtf\"\n", strcmp(st->tex[1].name, "materials/")?"materials/":"", st->tex[1].name);
|
|
}
|
|
else if (!Q_strcasecmp(st->type, "Decal"))
|
|
{
|
|
Q_strlcpy(st->type, "vmt/vertexlit", sizeof(st->type));
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tprogram \"%s%s\"\n", st->type, progargs);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tdiffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tpolygonOffset 1\n");
|
|
}
|
|
else if (!Q_strcasecmp(st->type, "DecalModulate"))
|
|
{
|
|
Q_strlcatfz(script, &offset, sizeof(script),
|
|
"\t{\n"
|
|
"\t\tprogram \"vmt/vertexlit%s\"\n"
|
|
"\t\tblendFunc gl_dst_color gl_one_minus_src_alpha\n"
|
|
"\t}\n", progargs);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tdiffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tpolygonOffset 1\n");
|
|
}
|
|
else if (!Q_strcasecmp(st->type, "Water"))
|
|
{
|
|
Q_strlcatfz(script, &offset, sizeof(script),
|
|
"\t{\n"
|
|
"\t\tprogram \"vmt/water%s\"\n"
|
|
"\t\tmap $refraction\n"
|
|
"\t\tmap $reflection\n"
|
|
"\t}\n", progargs);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tdiffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tnormalmap \"%s%s.vtf\"\n", strcmp(st->normalmap, "materials/")?"materials/":"", st->normalmap);
|
|
}
|
|
else if (!Q_strcasecmp(st->type, "Refract"))
|
|
{
|
|
Q_strlcatfz(script, &offset, sizeof(script),
|
|
"\t{\n"
|
|
"\t\tprogram \"vmt/refract%s\"\n"
|
|
"\t\tmap $refraction\n"
|
|
"\t}\n", progargs);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tdiffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tnormalmap \"%s%s.vtf\"\n", strcmp(st->normalmap, "materials/")?"materials/":"", st->normalmap);
|
|
}
|
|
else if (!Q_strcasecmp(st->type, "VertexlitGeneric"))
|
|
{
|
|
if (*st->envmap && st->envfrombase)
|
|
{
|
|
if (st->halflambert)
|
|
Q_strlcpy(st->type, "vmt/vertexlit#ENVFROMBASE#HALFLAMBERT", sizeof(st->type));
|
|
else
|
|
Q_strlcpy(st->type, "vmt/vertexlit#ENVFROMBASE", sizeof(st->type));
|
|
}
|
|
else
|
|
{
|
|
if (st->halflambert)
|
|
Q_strlcpy(st->type, "vmt/vertexlit#HALFLAMBERT", sizeof(st->type));
|
|
else
|
|
Q_strlcpy(st->type, "vmt/vertexlit", sizeof(st->type));
|
|
}
|
|
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tprogram \"%s%s\"\n", st->type, progargs);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tdiffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
|
|
|
|
if (*st->normalmap)
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tnormalmap \"%s%s.vtf\"\n", strcmp(st->normalmap, "materials/")?"materials/":"", st->normalmap);
|
|
}
|
|
else if (!Q_strcasecmp(st->type, "LightmappedGeneric"))
|
|
{
|
|
/* reflectmask from diffuse map alpha */
|
|
if (*st->envmap && st->envfrombase)
|
|
Q_strlcpy(st->type, "vmt/lightmapped#ENVFROMBASE", sizeof(st->type));
|
|
else if (*st->envmap && *st->envmapmask) /* dedicated reflectmask */
|
|
Q_strlcpy(st->type, "vmt/lightmapped#ENVFROMMASK", sizeof(st->type));
|
|
else /* take from normalmap */
|
|
Q_strlcpy(st->type, "vmt/lightmapped", sizeof(st->type));
|
|
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tprogram \"%s%s\"\n", st->type, progargs);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tdiffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
|
|
|
|
if (*st->normalmap)
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tnormalmap \"%s%s.vtf\"\n", strcmp(st->normalmap, "materials/")?"materials/":"", st->normalmap);
|
|
}
|
|
else
|
|
{
|
|
/* render-target camera/monitor - eukara*/
|
|
if (!Q_strcasecmp(st->tex[0].name, "_rt_Camera"))
|
|
Q_strlcatfz(script, &offset, sizeof(script),
|
|
"\t{\n"
|
|
"\t\tmap $rt:base\n"
|
|
"\t}\n"/*, progargs*/);
|
|
else
|
|
{
|
|
/* the default should just be unlit, let's not make any assumptions - eukara*/
|
|
Q_strlcpy(st->type, "vmt/unlit", sizeof(st->type));
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tprogram \"%s%s\"\n", st->type, progargs);
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tdiffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
|
|
}
|
|
}
|
|
|
|
if (*st->envmapmask)
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\treflectmask \"%s%s.vtf\"\n", strcmp(st->envmapmask, "materials/")?"materials/":"", st->envmapmask);
|
|
if (*st->envmap && strcmp(st->envmap, "env_cubemap"))
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\treflectcube \"%s%s.vtf\"\n", strcmp(st->envmap, "materials/")?"materials/":"", st->envmap);
|
|
if (st->alphatest)
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\talphatest ge128\n");
|
|
if (st->culldisable)
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tcull disable\n");
|
|
if (st->ignorez)
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tnodepth\n");
|
|
if (st->blendfunc)
|
|
Q_strlcatfz(script, &offset, sizeof(script), "\tprogblendfunc %s\n", st->blendfunc);
|
|
|
|
Q_strlcatfz(script, &offset, sizeof(script), "}\n");
|
|
|
|
LoadMaterialString(ps, script);
|
|
|
|
if (st->sourcefile)
|
|
{ //cat the original file on there...
|
|
if (st->savefile)
|
|
{
|
|
char *winsucks; //strip any '\r' chars in there that like to show as ugly glyphs.
|
|
for (winsucks = st->sourcefile; *winsucks; winsucks++)
|
|
if (*winsucks=='\r')
|
|
*winsucks = ' ';
|
|
|
|
Q_StrCat(st->savefile, "\n/*\n");
|
|
Q_StrCat(st->savefile, st->sourcefile);
|
|
Q_StrCat(st->savefile, "*/");
|
|
}
|
|
plugfuncs->Free(st->sourcefile);
|
|
}
|
|
}
|
|
static qboolean VMT_ReadVMT(const char *fname, vmtstate_t *st)
|
|
{
|
|
char *line, *file = NULL;
|
|
com_tokentype_t ttype;
|
|
char token[MAX_QPATH];
|
|
char *prefix="", *postfix="";
|
|
|
|
//don't dupe the mandatory materials/ prefix
|
|
if (strncmp(fname, "materials/", 10))
|
|
prefix = "materials/";
|
|
if (strcmp(fsfuncs->GetExtension(fname, NULL), ".vmt"))
|
|
postfix = ".vmt";
|
|
Q_snprintfz(token, sizeof(token), "%s%s%s", prefix, fname, postfix);
|
|
|
|
file = fsfuncs->LoadFile(token, NULL);
|
|
if (file)
|
|
{
|
|
if (st->savefile)
|
|
{
|
|
if (st->sourcefile)
|
|
{
|
|
Q_StrCat(&st->sourcefile, fname);
|
|
Q_StrCat(&st->sourcefile, ":\n");
|
|
Q_StrCat(&st->sourcefile, file);
|
|
}
|
|
else
|
|
Q_StrCat(&st->sourcefile, file);
|
|
}
|
|
|
|
line = file;
|
|
line = cmdfuncs->ParseToken(line, st->type, sizeof(st->type), &ttype);
|
|
line = cmdfuncs->ParseToken(line, token, sizeof(token), &ttype);
|
|
if (!strcmp(token, "{"))
|
|
{
|
|
line = VMT_ParseBlock(fname, st, line);
|
|
}
|
|
|
|
plugfuncs->Free(file);
|
|
return !!line;
|
|
}
|
|
return false;
|
|
}
|
|
static qboolean Shader_LoadVMT(parsestate_t *ps, const char *filename, void (*LoadMaterialString)(parsestate_t *ps, const char *script))
|
|
{
|
|
vmtstate_t st;
|
|
memset(&st, 0, sizeof(st));
|
|
st.savefile = NULL;//ps->saveshaderbody;
|
|
if (!VMT_ReadVMT(filename, &st))
|
|
{
|
|
if (st.sourcefile)
|
|
plugfuncs->Free(st.sourcefile);
|
|
return false;
|
|
}
|
|
|
|
Shader_GenerateFromVMT(ps, &st, filename, LoadMaterialString);
|
|
return true;
|
|
}
|
|
|
|
static struct sbuiltin_s vmtprograms[] =
|
|
{
|
|
//we don't know what renderer the engine will need...
|
|
#ifdef FTEPLUGIN
|
|
#ifndef GLQUAKE
|
|
#define GLQUAKE
|
|
#endif
|
|
#ifndef VKQUAKE
|
|
#define VKQUAKE
|
|
#endif
|
|
#ifndef D3DQUAKE
|
|
#define D3DQUAKE
|
|
#endif
|
|
#endif
|
|
#include "mat_vmt_progs.h"
|
|
{QR_NONE}
|
|
};
|
|
static plugmaterialloaderfuncs_t vmtfuncs =
|
|
{
|
|
"HL2 VMT",
|
|
Shader_LoadVMT,
|
|
|
|
vmtprograms,
|
|
};
|
|
|
|
qboolean VMT_Init(void)
|
|
{
|
|
fsfuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*fsfuncs));
|
|
if (!fsfuncs)
|
|
return false;
|
|
return plugfuncs->ExportInterface(plugmaterialloaderfuncs_name, &vmtfuncs, sizeof(vmtfuncs));
|
|
} |