2021-11-08 08:47:05 +00:00
# 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
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/transition#TWOWAY " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t program \" %s%s \" \n " , st - > type , progargs ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t diffusemap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 0 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 0 ] . name ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t uppermap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 1 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 1 ] . name ) ;
}
else if ( ! Q_strcasecmp ( st - > type , " Decal " ) )
{
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/vertexlit " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t program \" %s%s \" \n " , st - > type , progargs ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t diffusemap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 0 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 0 ] . name ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t polygonOffset 1 \n " ) ;
}
else if ( ! Q_strcasecmp ( st - > type , " DecalModulate " ) )
{
Q_strlcatfz ( script , & offset , sizeof ( script ) ,
" \t { \n "
2021-11-08 08:47:27 +00:00
" \t \t program \" vmt/vertexlit%s \" \n "
2021-11-08 08:47:05 +00:00
" \t \t blendFunc gl_dst_color gl_one_minus_src_alpha \n "
" \t } \n " , progargs ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t diffusemap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 0 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 0 ] . name ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t polygonOffset 1 \n " ) ;
}
else if ( ! Q_strcasecmp ( st - > type , " Water " ) )
{
Q_strlcatfz ( script , & offset , sizeof ( script ) ,
" \t { \n "
2021-11-08 08:47:27 +00:00
" \t \t program \" vmt/water%s \" \n "
2021-11-08 08:47:05 +00:00
" \t \t map $refraction \n "
" \t \t map $reflection \n "
" \t } \n " , progargs ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t diffusemap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 0 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 0 ] . name ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t normalmap \" %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 "
2021-11-08 08:47:27 +00:00
" \t \t program \" vmt/refract%s \" \n "
2021-11-08 08:47:05 +00:00
" \t \t map $refraction \n "
" \t } \n " , progargs ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t diffusemap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 0 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 0 ] . name ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t normalmap \" %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 )
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/vertexlit#ENVFROMBASE#HALFLAMBERT " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
else
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/vertexlit#ENVFROMBASE " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
}
else
{
if ( st - > halflambert )
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/vertexlit#HALFLAMBERT " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
else
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/vertexlit " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
}
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t program \" %s%s \" \n " , st - > type , progargs ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t diffusemap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 0 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 0 ] . name ) ;
if ( * st - > normalmap )
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t normalmap \" %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 )
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/lightmapped#ENVFROMBASE " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
else if ( * st - > envmap & & * st - > envmapmask ) /* dedicated reflectmask */
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/lightmapped#ENVFROMMASK " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
else /* take from normalmap */
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/lightmapped " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t program \" %s%s \" \n " , st - > type , progargs ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t diffusemap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 0 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 0 ] . name ) ;
if ( * st - > normalmap )
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t normalmap \" %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 \t map $rt:base \n "
" \t } \n " /*, progargs*/ ) ;
else
{
/* the default should just be unlit, let's not make any assumptions - eukara*/
2021-11-08 08:47:27 +00:00
Q_strlcpy ( st - > type , " vmt/unlit " , sizeof ( st - > type ) ) ;
2021-11-08 08:47:05 +00:00
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t program \" %s%s \" \n " , st - > type , progargs ) ;
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t diffusemap \" %s%s.vtf \" \n " , strcmp ( st - > tex [ 0 ] . name , " materials/ " ) ? " materials/ " : " " , st - > tex [ 0 ] . name ) ;
}
}
if ( * st - > envmapmask )
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t reflectmask \" %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 ) , " \t reflectcube \" %s%s.vtf \" \n " , strcmp ( st - > envmap , " materials/ " ) ? " materials/ " : " " , st - > envmap ) ;
if ( st - > alphatest )
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t alphatest ge128 \n " ) ;
if ( st - > culldisable )
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t cull disable \n " ) ;
if ( st - > ignorez )
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t nodepth \n " ) ;
if ( st - > blendfunc )
Q_strlcatfz ( script , & offset , sizeof ( script ) , " \t progblendfunc %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 = " " ;
2024-04-25 05:57:34 +00:00
if ( strstr ( fname , " :// " ) )
return false ; //don't try to handle urls.
2021-11-08 08:47:05 +00:00
//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 ;
}
2021-11-08 08:47:27 +00:00
static struct sbuiltin_s vmtprograms [ ] =
{
2021-11-10 01:36:22 +00:00
//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
2021-11-08 08:47:27 +00:00
# include "mat_vmt_progs.h"
{ QR_NONE }
} ;
2021-11-08 08:47:05 +00:00
static plugmaterialloaderfuncs_t vmtfuncs =
{
" HL2 VMT " ,
Shader_LoadVMT ,
2021-11-08 08:47:27 +00:00
vmtprograms ,
2021-11-08 08:47:05 +00:00
} ;
qboolean VMT_Init ( void )
{
fsfuncs = plugfuncs - > GetEngineInterface ( plugfsfuncs_name , sizeof ( * fsfuncs ) ) ;
if ( ! fsfuncs )
return false ;
return plugfuncs - > ExportInterface ( plugmaterialloaderfuncs_name , & vmtfuncs , sizeof ( vmtfuncs ) ) ;
}