first public attempt at pbr.
update infoblobs to be slightly more self-contained (still not finalised). q3ui can now change audio volumes. linearise 16bit srgb textures as required. code can now potentially support >256 bones. disabled until the stack overflows are fixed... remap bone indexes where required, for a 10-fold speedup on models with otherwise-too-high bone counts gltf loader updates, primarily shader changes, for better conformance. shaders can now specify whether a texture should be treated as srgb or not. implement serverside download queue for ezquake/legacy clients downloading multiple demos. fte clients should never need to use this (would break total download size display). some work towards threading shader loading. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5430 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
d6d8d4c695
commit
5e7688a590
41 changed files with 1902 additions and 882 deletions
|
@ -3612,7 +3612,7 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp
|
|||
VectorCopy(snew->angles, le->newangle);
|
||||
|
||||
//fixme: should be oldservertime
|
||||
le->orglerpdeltatime = servertime-le->orglerpstarttime;
|
||||
le->orglerpdeltatime = bound(0.001, servertime-le->orglerpstarttime, cl_lerp_maxinterval.value);
|
||||
le->orglerpstarttime = servertime;
|
||||
}
|
||||
|
||||
|
|
|
@ -1922,7 +1922,7 @@ static void CL_SendUserinfoUpdate(void)
|
|||
size_t bloboffset = cls.userinfosync.keys[0].syncpos;
|
||||
unsigned int seat = info - cls.userinfo;
|
||||
size_t blobsize;
|
||||
const char *blobdata = InfoBuf_BlobForKey(info, key, &blobsize);
|
||||
const char *blobdata = InfoBuf_BlobForKey(info, key, &blobsize, NULL);
|
||||
size_t sendsize = blobsize - bloboffset;
|
||||
|
||||
const char *s;
|
||||
|
|
|
@ -5272,6 +5272,41 @@ static void CL_UpdateUserinfo (void)
|
|||
}
|
||||
}
|
||||
|
||||
static void CL_ParseSetInfoBlob (void)
|
||||
{
|
||||
qbyte slot = MSG_ReadByte();
|
||||
char *key = MSG_ReadString();
|
||||
size_t keysize;
|
||||
unsigned int offset = MSG_ReadLong();
|
||||
qboolean final = !!(offset & 0x80000000);
|
||||
unsigned short valsize = MSG_ReadShort();
|
||||
char *val = BZ_Malloc(valsize);
|
||||
MSG_ReadData(val, valsize);
|
||||
offset &= ~0x80000000;
|
||||
key = InfoBuf_DecodeString(key, key+strlen(key), &keysize);
|
||||
|
||||
if (slot-- == 0)
|
||||
InfoBuf_SyncReceive(&cl.serverinfo, key, keysize, val, valsize, offset, final);
|
||||
else if (slot >= MAX_CLIENTS)
|
||||
Con_Printf("INVALID SETINFO %i: %s=%s\n", slot, key, val);
|
||||
else
|
||||
{
|
||||
player_info_t *player = &cl.players[slot];
|
||||
if (offset)
|
||||
Con_DLPrintf(2,"SETINFO %s: %s+=%s\n", player->name, key, val);
|
||||
else
|
||||
Con_DLPrintf(strcmp(key, "chat")?1:2,"SETINFO %s: %s=%s\n", player->name, key, val);
|
||||
|
||||
InfoBuf_SyncReceive(&player->userinfo, key, keysize, val, valsize, offset, final);
|
||||
player->userinfovalid = true;
|
||||
|
||||
if (final)
|
||||
CL_ProcessUserInfo (slot, player);
|
||||
}
|
||||
|
||||
Z_Free(key);
|
||||
Z_Free(val);
|
||||
}
|
||||
/*
|
||||
==============
|
||||
CL_SetInfo
|
||||
|
@ -5281,67 +5316,27 @@ static void CL_ParseSetInfo (void)
|
|||
{
|
||||
int slot;
|
||||
player_info_t *player;
|
||||
char *temp;
|
||||
char *key;
|
||||
char *val;
|
||||
unsigned int offset;
|
||||
qboolean final;
|
||||
size_t keysize;
|
||||
size_t valsize;
|
||||
char key[512];
|
||||
|
||||
slot = MSG_ReadByte ();
|
||||
|
||||
if (slot == 255 && (cls.fteprotocolextensions2 & PEXT2_INFOBLOBS))
|
||||
{
|
||||
slot = MSG_ReadByte();
|
||||
offset = MSG_ReadLong();
|
||||
final = !!(offset & 0x80000000);
|
||||
offset &= ~0x80000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
final = true;
|
||||
offset = 0;
|
||||
}
|
||||
MSG_ReadStringBuffer(key, sizeof(key));
|
||||
val = MSG_ReadString();
|
||||
|
||||
temp = MSG_ReadString();
|
||||
if (cls.fteprotocolextensions2 & PEXT2_INFOBLOBS)
|
||||
key = InfoBuf_DecodeString(temp, temp+strlen(temp), &keysize);
|
||||
else
|
||||
{
|
||||
keysize = strlen(temp);
|
||||
key = Z_StrDup(temp);
|
||||
}
|
||||
|
||||
temp = MSG_ReadString();
|
||||
if (cls.fteprotocolextensions2 & PEXT2_INFOBLOBS)
|
||||
val = InfoBuf_DecodeString(temp, temp+strlen(temp), &valsize);
|
||||
else
|
||||
{
|
||||
valsize = strlen(temp);
|
||||
val = Z_StrDup(temp);
|
||||
}
|
||||
|
||||
if (slot == 255)
|
||||
InfoBuf_SyncReceive(&cl.serverinfo, key, keysize, val, valsize, offset, final);
|
||||
else if (slot >= MAX_CLIENTS)
|
||||
if (slot >= MAX_CLIENTS)
|
||||
Con_Printf("INVALID SETINFO %i: %s=%s\n", slot, key, val);
|
||||
else
|
||||
{
|
||||
player = &cl.players[slot];
|
||||
|
||||
if (offset)
|
||||
Con_DLPrintf(2,"SETINFO %s: %s+=%s\n", player->name, key, val);
|
||||
else
|
||||
Con_DLPrintf(strcmp(key, "chat")?1:2,"SETINFO %s: %s=%s\n", player->name, key, val);
|
||||
Con_DLPrintf(strcmp(key, "chat")?1:2,"SETINFO %s: %s=%s\n", player->name, key, val);
|
||||
|
||||
InfoBuf_SyncReceive(&player->userinfo, key, keysize, val, valsize, offset, final);
|
||||
InfoBuf_SetStarKey(&player->userinfo, key, val);
|
||||
player->userinfovalid = true;
|
||||
|
||||
CL_ProcessUserInfo (slot, player);
|
||||
}
|
||||
Z_Free(key);
|
||||
Z_Free(val);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -7160,10 +7155,12 @@ void CLQW_ParseServerMessage (void)
|
|||
case svc_setinfo:
|
||||
CL_ParseSetInfo ();
|
||||
break;
|
||||
|
||||
case svc_serverinfo:
|
||||
CL_ServerInfo ();
|
||||
break;
|
||||
case svcfte_setinfoblob:
|
||||
CL_ParseSetInfoBlob();
|
||||
break;
|
||||
|
||||
case svc_download:
|
||||
CL_ParseDownload (false);
|
||||
|
|
|
@ -1253,7 +1253,9 @@ static qintptr_t VARGS Plug_Mod_GetPluginModelFuncs(void *offset, quintptr_t mas
|
|||
#endif
|
||||
NULL,
|
||||
Image_GetTexture,
|
||||
FS_OpenVFS
|
||||
FS_OpenVFS,
|
||||
Mod_AccumulateTextureVectors,
|
||||
Mod_NormaliseTextureVectors,
|
||||
};
|
||||
if (VM_LONG(arg[0]) >= sizeof(funcs))
|
||||
return (qintptr_t)&funcs;
|
||||
|
|
|
@ -696,7 +696,53 @@ void UI_RegisterFont(char *fontName, int pointSize, fontInfo_t *font)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static cvar_t *Cvar_Q3FindVar (const char *var_name)
|
||||
{
|
||||
struct {
|
||||
const char *q3;
|
||||
const char *fte;
|
||||
} cvarremaps[] =
|
||||
{
|
||||
{"s_musicvolume", "bgmvolume"},
|
||||
{"r_gamma", "gamma"},
|
||||
{"s_sdlSpeed", "s_khz"},
|
||||
{"r_fullscreen", "vid_fullscreen"},
|
||||
{"r_picmip", "gl_picmip"},
|
||||
{"r_textureMode", "gl_texturemode"},
|
||||
{"r_lodBias", "d_lodbias"},
|
||||
{"r_colorbits", "vid_bpp"},
|
||||
{"r_dynamiclight", "r_dynamic"},
|
||||
{"r_finish", "gl_finish"},
|
||||
// {"r_glDriver", NULL},
|
||||
// {"r_depthbits", NULL},
|
||||
// {"r_stencilbits", NULL},
|
||||
// {"s_compression", NULL},
|
||||
// {"r_texturebits", NULL},
|
||||
// {"r_allowExtensions",NULL},
|
||||
// {"s_useOpenAL", NULL},
|
||||
// {"sv_running", NULL},
|
||||
// {"sv_killserver", NULL},
|
||||
// {"color1", NULL},
|
||||
// {"in_joystick", NULL},
|
||||
// {"joy_threshold", NULL},
|
||||
// {"cl_freelook", NULL},
|
||||
// {"color1", NULL},
|
||||
// {"r_availableModes",NULL},
|
||||
// {"r_mode", NULL},
|
||||
};
|
||||
cvar_t *v;
|
||||
size_t i;
|
||||
v = Cvar_FindVar(var_name);
|
||||
if (v)
|
||||
return v;
|
||||
for (i = 0; i < countof(cvarremaps); i++)
|
||||
{
|
||||
if (!strcmp(cvarremaps[i].q3, var_name))
|
||||
return Cvar_FindVar(cvarremaps[i].fte);
|
||||
}
|
||||
// Con_Printf("Q3 Cvar %s is not known\n", var_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define VALIDATEPOINTER(o,l) if ((quintptr_t)o + l >= mask || VM_POINTER(o) < offset) Host_EndGame("Call to ui trap %i passes invalid pointer\n", (int)fn); //out of bounds.
|
||||
|
||||
|
@ -752,7 +798,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
|||
}
|
||||
else
|
||||
{
|
||||
var = Cvar_FindVar(vname);
|
||||
var = Cvar_Q3FindVar(vname);
|
||||
if (var)
|
||||
Cvar_Set(var, vval); //set it
|
||||
else
|
||||
|
@ -764,7 +810,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
|||
{
|
||||
cvar_t *var;
|
||||
char *vname = VM_POINTER(arg[0]);
|
||||
var = Cvar_FindVar(vname);
|
||||
var = Cvar_Q3FindVar(vname);
|
||||
if (var)
|
||||
VM_FLOAT(ret) = var->value;
|
||||
else
|
||||
|
@ -775,7 +821,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
|||
{
|
||||
cvar_t *var;
|
||||
char *vname = VM_POINTER(arg[0]);
|
||||
var = Cvar_FindVar(vname);
|
||||
var = Cvar_Q3FindVar(vname);
|
||||
if (!VM_LONG(arg[2]))
|
||||
VM_LONG(ret) = 0;
|
||||
else if (!var)
|
||||
|
@ -794,14 +840,14 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
|||
break;
|
||||
|
||||
case UI_CVAR_SETVALUE:
|
||||
Cvar_SetValue(Cvar_FindVar(VM_POINTER(arg[0])), VM_FLOAT(arg[1]));
|
||||
Cvar_SetValue(Cvar_Q3FindVar(VM_POINTER(arg[0])), VM_FLOAT(arg[1]));
|
||||
break;
|
||||
|
||||
case UI_CVAR_RESET: //cvar reset
|
||||
{
|
||||
cvar_t *var;
|
||||
char *vname = VM_POINTER(arg[0]);
|
||||
var = Cvar_FindVar(vname);
|
||||
var = Cvar_Q3FindVar(vname);
|
||||
if (var)
|
||||
Cvar_Set(var, var->defaultstr);
|
||||
}
|
||||
|
|
|
@ -2975,7 +2975,9 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
playerview_t pv;
|
||||
entity_t ent;
|
||||
vec3_t fwd, rgt, up;
|
||||
vec3_t lightpos = {0, 1, 0};
|
||||
vec3_t lightpos = {1, 1, 0};
|
||||
float transforms[12];
|
||||
float scale;
|
||||
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
@ -3003,15 +3005,14 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
|
||||
VectorClear(r_refdef.viewangles);
|
||||
r_refdef.viewangles[0] = 20;
|
||||
r_refdef.viewangles[1] = realtime * 90;
|
||||
// r_refdef.viewangles[1] = realtime * 90;
|
||||
AngleVectors(r_refdef.viewangles, fwd, rgt, up);
|
||||
VectorScale(fwd, -64, r_refdef.vieworg);
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ent.scale = 1;
|
||||
// ent.angles[1] = realtime*45;//mods->yaw;
|
||||
ent.angles[1] = realtime*90;//mods->yaw;
|
||||
// ent.angles[0] = realtime*23.4;//mods->pitch;
|
||||
|
||||
ent.angles[0]*=r_meshpitch.value;
|
||||
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
||||
ent.angles[0]*=r_meshpitch.value;
|
||||
|
@ -3020,8 +3021,16 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
ent.model = model;
|
||||
if (!ent.model)
|
||||
return; //panic!
|
||||
//ent.origin[2] -= (ent.model->maxs[2]-ent.model->mins[2]) * 0.5 + ent.model->mins[2];
|
||||
|
||||
ent.scale = 1;
|
||||
scale = max(max(fabs(ent.model->maxs[0]-ent.model->mins[0]), fabs(ent.model->maxs[1]-ent.model->mins[1])), fabs(ent.model->maxs[2]-ent.model->mins[2]));
|
||||
scale = scale?64.0/scale:1;
|
||||
ent.origin[2] -= (ent.model->maxs[2]-ent.model->mins[2]) * 0.5 + ent.model->mins[2];
|
||||
Vector4Set(ent.shaderRGBAf, 1, 1, 1, 1);
|
||||
VectorScale(ent.axis[0], scale, ent.axis[0]);
|
||||
VectorScale(ent.axis[1], scale, ent.axis[1]);
|
||||
VectorScale(ent.axis[2], scale, ent.axis[2]);
|
||||
/*if (strstr(model->name, "player"))
|
||||
{
|
||||
ent.bottomcolour = genhsv(realtime*0.1 + 0, 1, 1);
|
||||
|
@ -3042,11 +3051,49 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
ent.framestate.g[FS_REG].endbone = 0x7fffffff;
|
||||
// ent.customskin = Mod_RegisterSkinFile(va("%s_0.skin", mods->modelname));
|
||||
|
||||
VectorSet(ent.glowmod, 1,1,1);
|
||||
ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66;
|
||||
ent.light_range[0] = ent.light_range[1] = ent.light_range[2] = 0.33;
|
||||
|
||||
V_ApplyRefdef();
|
||||
|
||||
if (ent.model->camerabone>0 && Mod_GetTag(ent.model, ent.model->camerabone, &ent.framestate, transforms))
|
||||
{
|
||||
VectorClear(ent.origin);
|
||||
ent.angles[0]*=r_meshpitch.value;
|
||||
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
||||
ent.angles[0]*=r_meshpitch.value;
|
||||
VectorInverse(ent.axis[1]);
|
||||
scale = 1;
|
||||
{
|
||||
vec3_t fwd, up;
|
||||
float camera[12], et[12] = {
|
||||
ent.axis[0][0], ent.axis[1][0], ent.axis[2][0], ent.origin[0],
|
||||
ent.axis[0][1], ent.axis[1][1], ent.axis[2][1], ent.origin[1],
|
||||
ent.axis[0][2], ent.axis[1][2], ent.axis[2][2], ent.origin[2],
|
||||
};
|
||||
|
||||
R_ConcatTransforms((void*)et, (void*)transforms, (void*)camera);
|
||||
VectorSet(fwd, camera[2], camera[6], camera[10]);
|
||||
VectorNegate(fwd, fwd);
|
||||
VectorSet(up, camera[1], camera[5], camera[9]);
|
||||
VectorSet(r_refdef.vieworg, camera[3], camera[7], camera[11]);
|
||||
VectorAngles(fwd, up, r_refdef.viewangles, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ent.angles[1] = realtime*90;//mods->yaw;
|
||||
ent.angles[0]*=r_meshpitch.value;
|
||||
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
||||
ent.angles[0]*=r_meshpitch.value;
|
||||
VectorScale(ent.axis[0], scale, ent.axis[0]);
|
||||
VectorScale(ent.axis[1], -scale, ent.axis[1]);
|
||||
VectorScale(ent.axis[2], scale, ent.axis[2]);
|
||||
}
|
||||
|
||||
ent.scale = scale;
|
||||
|
||||
VectorNormalize(lightpos);
|
||||
ent.light_dir[0] = DotProduct(lightpos, ent.axis[0]);
|
||||
ent.light_dir[1] = DotProduct(lightpos, ent.axis[1]);
|
||||
|
|
|
@ -7602,6 +7602,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
|
||||
switch(nf)
|
||||
{
|
||||
case PTI_R8:
|
||||
case PTI_L8:
|
||||
for (i = 0; i < m; i++)
|
||||
((qbyte*)rgbadata)[i+0] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+0] * (1.0/255));
|
||||
|
@ -7611,6 +7612,19 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
for (i = 0; i < m; i+=2)
|
||||
((qbyte*)rgbadata)[i+0] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+0] * (1.0/255));
|
||||
break;
|
||||
case PTI_R16:
|
||||
for (i = 0; i < m; i+=4)
|
||||
((unsigned short*)rgbadata)[i+0] = 0xffff*Image_LinearFloatFromsRGBFloat(((unsigned short*)rgbadata)[i+0] * (1.0/0xffff));
|
||||
break;
|
||||
case PTI_RGBA16:
|
||||
m*=4;
|
||||
for (i = 0; i < m; i+=4)
|
||||
{
|
||||
((unsigned short*)rgbadata)[i+0] = 0xffff*Image_LinearFloatFromsRGBFloat(((unsigned short*)rgbadata)[i+0] * (1.0/0xffff));
|
||||
((unsigned short*)rgbadata)[i+1] = 0xffff*Image_LinearFloatFromsRGBFloat(((unsigned short*)rgbadata)[i+1] * (1.0/0xffff));
|
||||
((unsigned short*)rgbadata)[i+2] = 0xffff*Image_LinearFloatFromsRGBFloat(((unsigned short*)rgbadata)[i+2] * (1.0/0xffff));
|
||||
}
|
||||
break;
|
||||
case PTI_RGBA8:
|
||||
case PTI_RGBX8:
|
||||
case PTI_BGRA8:
|
||||
|
@ -7627,7 +7641,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
case PTI_BC1_RGBA:
|
||||
case PTI_BC2_RGBA:
|
||||
case PTI_BC3_RGBA:
|
||||
//FIXME: bc1/2/3 has two leading 16bit values per block.
|
||||
//FIXME: bc1/2/3 has two leading 16bit 565 values per block.
|
||||
default:
|
||||
//these formats are weird. we can't just fiddle with the rgbdata
|
||||
//FIXME: etc2 has all sorts of weird encoding tables...
|
||||
|
@ -8656,7 +8670,7 @@ image_t *QDECL Image_GetTexture(const char *identifier, const char *subpath, uns
|
|||
|
||||
qboolean dontposttoworker = (flags & (IF_NOWORKER | IF_LOADNOW));
|
||||
qboolean lowpri = (flags & IF_LOWPRIORITY);
|
||||
// qboolean highpri = (flags & IF_HIGHPRIORITY);
|
||||
qboolean highpri = (flags & IF_HIGHPRIORITY);
|
||||
flags &= ~(IF_LOADNOW | IF_LOWPRIORITY | IF_HIGHPRIORITY);
|
||||
|
||||
#ifdef LOADERTHREAD
|
||||
|
@ -8782,7 +8796,9 @@ image_t *QDECL Image_GetTexture(const char *identifier, const char *subpath, uns
|
|||
}
|
||||
else
|
||||
#endif
|
||||
if (lowpri)
|
||||
if (highpri)
|
||||
COM_InsertWork(WG_LOADER, Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
|
||||
else if (lowpri)
|
||||
COM_AddWork(WG_LOADER, Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
|
||||
else
|
||||
COM_AddWork(WG_LOADER, Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
|
||||
|
|
|
@ -3254,7 +3254,6 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
|
|||
VectorScale(fwd, -mods->dist, r_refdef.vieworg);
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ent.scale = 1;
|
||||
// ent.angles[1] = realtime*45;//mods->yaw;
|
||||
// ent.angles[0] = realtime*23.4;//mods->pitch;
|
||||
|
||||
|
@ -3266,8 +3265,18 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
|
|||
ent.model = Mod_ForName(mods->modelname, MLV_WARN);
|
||||
if (!ent.model)
|
||||
return; //panic!
|
||||
ent.origin[2] -= (ent.model->maxs[2]-ent.model->mins[2]) * 0.5 + ent.model->mins[2];
|
||||
ent.scale = max(max(fabs(ent.model->maxs[0]-ent.model->mins[0]), fabs(ent.model->maxs[1]-ent.model->mins[1])), fabs(ent.model->maxs[2]-ent.model->mins[2]));
|
||||
ent.scale = ent.scale?64.0/ent.scale:1;
|
||||
ent.origin[2] -= (ent.model->maxs[2]-ent.model->mins[2]) * 0.5;// + ent.model->mins[2];
|
||||
ent.origin[2] *= ent.scale;
|
||||
Vector4Set(ent.shaderRGBAf, 1, 1, 1, 1);
|
||||
VectorSet(ent.glowmod, 1, 1, 1);
|
||||
|
||||
// VectorScale(ent.axis[0], ent.scale, ent.axis[0]);
|
||||
// VectorScale(ent.axis[1], ent.scale, ent.axis[1]);
|
||||
// VectorScale(ent.axis[2], ent.scale, ent.axis[2]);
|
||||
// ent.scale = 1;
|
||||
|
||||
if (strstr(mods->modelname, "player"))
|
||||
{
|
||||
ent.bottomcolour = genhsv(realtime*0.1 + 0, 1, 1);
|
||||
|
@ -3311,6 +3320,9 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
|
|||
VectorCopy(tr.endpos, lightpos);
|
||||
}
|
||||
*/
|
||||
lightpos[0] = sin(realtime*0.1);
|
||||
lightpos[1] = cos(realtime*0.1);
|
||||
lightpos[2] = 0;
|
||||
|
||||
VectorNormalize(lightpos);
|
||||
ent.light_dir[0] = DotProduct(lightpos, ent.axis[0]);
|
||||
|
@ -3619,12 +3631,14 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
|
|||
"body: %i\n"
|
||||
"geomset: %i %i%s\n"
|
||||
"numverts: %i\nnumtris: %i\n"
|
||||
"numbones: %i\n"
|
||||
, ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2],
|
||||
contents,
|
||||
inf->csurface.flags,
|
||||
inf->surfaceid,
|
||||
inf->geomset>=MAX_GEOMSETS?-1:inf->geomset, inf->geomid, inf->geomset>=MAX_GEOMSETS?" (always)":"",
|
||||
inf->numverts, inf->numindexes/3
|
||||
inf->numverts, inf->numindexes/3,
|
||||
inf->numbones
|
||||
)
|
||||
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
|
||||
}
|
||||
|
@ -3709,7 +3723,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
|
|||
shader->defaulttextures->base = skin->upperoverlay; //diffuse texture for the upper body(shirt colour). no alpha channel. added to base.rgb
|
||||
break;
|
||||
case 4:
|
||||
t = "LopwerMap";
|
||||
t = "LowerMap";
|
||||
shader->defaulttextures->base = skin->loweroverlay; //diffuse texture for the lower body(trouser colour). no alpha channel. added to base.rgb
|
||||
break;
|
||||
case 5:
|
||||
|
|
|
@ -1544,30 +1544,6 @@ static void CSQC_PolyFlush(void)
|
|||
csqc_poly_shader = NULL;
|
||||
}
|
||||
|
||||
static void Shader_PolygonShader(const char *shortname, shader_t *s, const void *args)
|
||||
{
|
||||
Shader_DefaultScript(shortname, s,
|
||||
"{\n"
|
||||
"if $lpp\n"
|
||||
"program lpp_skin\n"
|
||||
"else\n"
|
||||
"program defaultskin#NONORMALS\n"
|
||||
"endif\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"rgbgen vertex\n"
|
||||
"alphagen vertex\n"
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $fullbright\n"
|
||||
"blendfunc add\n"
|
||||
"}\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
if (!s->defaulttextures->base && (s->flags & SHADER_HASDIFFUSE))
|
||||
R_BuildDefaultTexnums(NULL, s, 0);
|
||||
}
|
||||
static shader_t *PR_R_PolygonShader(const char *shadername, qboolean twod)
|
||||
{
|
||||
extern shader_t *shader_draw_fill_trans;
|
||||
|
@ -3961,7 +3937,7 @@ static void QCBUILTIN PF_cs_serverkeyblob (pubprogfuncs_t *prinst, struct global
|
|||
}
|
||||
ptr = (struct reverbproperties_s*)(prinst->stringtable + qcptr);
|
||||
|
||||
blob = InfoBuf_BlobForKey(&cl.serverinfo, keyname, &blobsize);
|
||||
blob = InfoBuf_BlobForKey(&cl.serverinfo, keyname, &blobsize, NULL);
|
||||
|
||||
if (qcptr)
|
||||
{
|
||||
|
@ -4054,7 +4030,7 @@ static void QCBUILTIN PF_cs_getplayerkeyblob (pubprogfuncs_t *prinst, struct glo
|
|||
else
|
||||
{
|
||||
size_t blobsize = 0;
|
||||
const char *blob = InfoBuf_BlobForKey(&cl.players[pnum].userinfo, keyname, &blobsize);
|
||||
const char *blob = InfoBuf_BlobForKey(&cl.players[pnum].userinfo, keyname, &blobsize, NULL);
|
||||
|
||||
if (qcptr)
|
||||
{
|
||||
|
|
|
@ -355,6 +355,7 @@ typedef enum
|
|||
WG_COUNT = 2 //main and loaders
|
||||
} wgroup_t;
|
||||
void COM_AddWork(wgroup_t thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b);
|
||||
void COM_InsertWork(wgroup_t tg, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b);
|
||||
qboolean COM_HasWork(void);
|
||||
void COM_WorkerFullSync(void);
|
||||
void COM_DestroyWorkerThread(void);
|
||||
|
|
|
@ -436,7 +436,6 @@ mpic_t *R2D_SafeCachePic (const char *path)
|
|||
|
||||
mpic_t *R2D_SafePicFromWad (const char *name)
|
||||
{
|
||||
void Shader_Default2D(const char *shortname, shader_t *s, const void *genargs);
|
||||
shader_t *s;
|
||||
if (!qrenderer)
|
||||
return NULL;
|
||||
|
|
|
@ -892,6 +892,7 @@ float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int
|
|||
int i;
|
||||
vec3_t ts, te;
|
||||
physent_t *pe;
|
||||
model_t *mod;
|
||||
int result=0;
|
||||
vec3_t axis[3];
|
||||
|
||||
|
@ -906,7 +907,8 @@ float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int
|
|||
pe = &pmove.physents[i];
|
||||
if (pe->nonsolid)
|
||||
continue;
|
||||
if (pe->model && pe->model->loadstate == MLS_LOADED)
|
||||
mod = pe->model;
|
||||
if (mod && mod->loadstate == MLS_LOADED && mod->funcs.NativeTrace)
|
||||
{
|
||||
VectorSubtract(start, pe->origin, ts);
|
||||
VectorSubtract(end, pe->origin, te);
|
||||
|
@ -914,10 +916,10 @@ float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int
|
|||
{
|
||||
AngleVectors(pe->angles, axis[0], axis[1], axis[2]);
|
||||
VectorNegate(axis[1], axis[1]);
|
||||
pe->model->funcs.NativeTrace(pe->model, 0, PE_FRAMESTATE, axis, ts, te, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &trace);
|
||||
mod->funcs.NativeTrace(mod, 0, PE_FRAMESTATE, axis, ts, te, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &trace);
|
||||
}
|
||||
else
|
||||
pe->model->funcs.NativeTrace(pe->model, 0, PE_FRAMESTATE, NULL, ts, te, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &trace);
|
||||
mod->funcs.NativeTrace(mod, 0, PE_FRAMESTATE, NULL, ts, te, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &trace);
|
||||
if (trace.fraction<1)
|
||||
{
|
||||
if (bestfrac > trace.fraction)
|
||||
|
|
|
@ -402,40 +402,45 @@ void R_RenderDlights (void);
|
|||
enum imageflags
|
||||
{
|
||||
/*warning: many of these flags only apply the first time it is requested*/
|
||||
IF_CLAMP = 1<<0, //disable texture coord wrapping.
|
||||
IF_NOMIPMAP = 1<<1, //disable mipmaps.
|
||||
IF_NEAREST = 1<<2, //force nearest
|
||||
IF_LINEAR = 1<<3, //force linear
|
||||
IF_UIPIC = 1<<4, //subject to texturemode2d
|
||||
//IF_DEPTHCMD=1<<5, //Reserved for d3d11
|
||||
IF_SRGB = 1<<6, //texture data is srgb
|
||||
IF_CLAMP = 1<<0, //disable texture coord wrapping.
|
||||
IF_NOMIPMAP = 1<<1, //disable mipmaps.
|
||||
IF_NEAREST = 1<<2, //force nearest
|
||||
IF_LINEAR = 1<<3, //force linear
|
||||
IF_UIPIC = 1<<4, //subject to texturemode2d
|
||||
//IF_DEPTHCMD = 1<<5, //Reserved for d3d11
|
||||
IF_SRGB = 1<<6, //texture data is srgb (read-as-linear)
|
||||
/*WARNING: If the above are changed, be sure to change shader pass flags*/
|
||||
|
||||
IF_NOPICMIP = 1<<7,
|
||||
IF_NOALPHA = 1<<8, /*hint rather than requirement*/
|
||||
IF_NOGAMMA = 1<<9,
|
||||
IF_3DMAP = 1<<10, /*waning - don't test directly*/
|
||||
IF_CUBEMAP = 1<<11, /*waning - don't test directly*/
|
||||
IF_TEXTYPE = (1<<10) | (1<<11), /*0=2d, 1=3d, 2=cubeface, 3=2d array texture*/
|
||||
IF_TEXTYPESHIFT = 10, /*0=2d, 1=3d, 2-7=cubeface*/
|
||||
IF_MIPCAP = 1<<12,
|
||||
IF_PREMULTIPLYALPHA = 1<<13, //rgb *= alpha
|
||||
IF_NOPICMIP = 1<<7,
|
||||
IF_NOALPHA = 1<<8, /*hint rather than requirement*/
|
||||
IF_NOGAMMA = 1<<9, /*do not apply texture-based gamma*/
|
||||
IF_3DMAP = 1<<10, /*waning - don't test directly*/
|
||||
IF_CUBEMAP = 1<<11, /*waning - don't test directly*/
|
||||
IF_TEXTYPE = (1<<10) | (1<<11), /*0=2d, 1=3d, 2=cubeface, 3=2d array texture*/
|
||||
IF_TEXTYPESHIFT = 10, /*0=2d, 1=3d, 2-7=cubeface*/
|
||||
IF_MIPCAP = 1<<12, //allow the use of d_mipcap
|
||||
IF_PREMULTIPLYALPHA = 1<<13, //rgb *= alpha
|
||||
|
||||
IF_WORLDTEX = 1<<18, //gl_picmip_world
|
||||
IF_SPRITETEX = 1<<19, //gl_picmip_sprites
|
||||
IF_NOSRGB = 1<<20, //ignore srgb when loading. this is guarenteed to be linear, for normalmaps etc.
|
||||
IF_UNUSED14 = 1<<14, //
|
||||
IF_UNUSED15 = 1<<15, //
|
||||
IF_UNUSED16 = 1<<16, //
|
||||
IF_UNUSED17 = 1<<17, //
|
||||
|
||||
IF_PALETTIZE = 1<<21,
|
||||
IF_NOPURGE = 1<<22,
|
||||
IF_HIGHPRIORITY = 1<<23,
|
||||
IF_LOWPRIORITY = 1<<24,
|
||||
IF_LOADNOW = 1<<25, /*hit the disk now, and delay the gl load until its actually needed. this is used only so that the width+height are known in advance*/
|
||||
IF_NOPCX = 1<<26, /*block pcx format. meaning qw skins can use team colours and cropping*/
|
||||
IF_TRYBUMP = 1<<27, /*attempt to load _bump if the specified _norm texture wasn't found*/
|
||||
IF_RENDERTARGET = 1<<28, /*never loaded from disk, loading can't fail*/
|
||||
IF_EXACTEXTENSION = 1<<29, /*don't mangle extensions, use what is specified and ONLY that*/
|
||||
IF_NOREPLACE = 1<<30, /*don't load a replacement, for some reason*/
|
||||
IF_NOWORKER = 1u<<31 /*don't pass the work to a loader thread. this gives fully synchronous loading. only valid from the main thread.*/
|
||||
IF_WORLDTEX = 1<<18, //gl_picmip_world
|
||||
IF_SPRITETEX = 1<<19, //gl_picmip_sprites
|
||||
IF_NOSRGB = 1<<20, //ignore srgb when loading. this is guarenteed to be linear, for normalmaps etc.
|
||||
|
||||
IF_PALETTIZE = 1<<21, //convert+load it as an RTI_P8 texture for the current palette/colourmap
|
||||
IF_NOPURGE = 1<<22, //texture is not flushed when no more shaders refer to it (for C code that holds a permanant reference to it - still purged on vid_reloads though)
|
||||
IF_HIGHPRIORITY = 1<<23, //pushed to start of worker queue instead of end...
|
||||
IF_LOWPRIORITY = 1<<24, //
|
||||
IF_LOADNOW = 1<<25, /*hit the disk now, and delay the gl load until its actually needed. this is used only so that the width+height are known in advance*/
|
||||
IF_NOPCX = 1<<26, /*block pcx format. meaning qw skins can use team colours and cropping*/
|
||||
IF_TRYBUMP = 1<<27, /*attempt to load _bump if the specified _norm texture wasn't found*/
|
||||
IF_RENDERTARGET = 1<<28, /*never loaded from disk, loading can't fail*/
|
||||
IF_EXACTEXTENSION = 1<<29, /*don't mangle extensions, use what is specified and ONLY that*/
|
||||
IF_NOREPLACE = 1<<30, /*don't load a replacement, for some reason*/
|
||||
IF_NOWORKER = 1u<<31 /*don't pass the work to a loader thread. this gives fully synchronous loading. only valid from the main thread.*/
|
||||
};
|
||||
|
||||
#define R_LoadTexture8(id,w,h,d,f,t) Image_GetTexture(id, NULL, f, d, NULL, w, h, t?TF_TRANS8:TF_SOLID8)
|
||||
|
|
|
@ -74,7 +74,7 @@ int sound_started=0;
|
|||
|
||||
cvar_t bgmvolume = CVARAFD( "musicvolume", "0.3", "bgmvolume", CVAR_ARCHIVE,
|
||||
"Volume level for background music.");
|
||||
cvar_t volume = CVARFD( "volume", "0.7", CVAR_ARCHIVE,
|
||||
cvar_t volume = CVARAFD( "volume", "0.7", /*q3*/"s_volume",CVAR_ARCHIVE,
|
||||
"Main volume level for all engine sound.");
|
||||
|
||||
cvar_t nosound = CVARFD( "nosound", "0", CVAR_ARCHIVE,
|
||||
|
|
|
@ -1011,9 +1011,13 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st
|
|||
return DEBUG_TRACE_OFF; //whoops
|
||||
}
|
||||
|
||||
if (reason)
|
||||
Con_Printf("QC Exception: %s\n", reason);
|
||||
|
||||
if (!pr_debugger.ival)
|
||||
{
|
||||
Con_Printf("Set %s to trace\n", pr_debugger.name);
|
||||
if (!stepasm && *filename)
|
||||
Con_Printf("Set %s to trace\n", pr_debugger.name);
|
||||
if (fatal)
|
||||
return DEBUG_TRACE_ABORT;
|
||||
return DEBUG_TRACE_OFF; //get lost
|
||||
|
|
|
@ -140,7 +140,7 @@ static clampedmodel_t clampedmodel[] = {
|
|||
|
||||
|
||||
|
||||
void Mod_AccumulateTextureVectors(vecV_t *const vc, vec2_t *const tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, const index_t *idx, int numidx, qboolean calcnorms)
|
||||
void QDECL Mod_AccumulateTextureVectors(vecV_t *const vc, vec2_t *const tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, const index_t *idx, int numidx, qboolean calcnorms)
|
||||
{
|
||||
int i;
|
||||
const float *v0, *v1, *v2;
|
||||
|
@ -215,7 +215,7 @@ void Mod_AccumulateMeshTextureVectors(mesh_t *m)
|
|||
Mod_AccumulateTextureVectors(m->xyz_array, m->st_array, m->normals_array, m->snormals_array, m->tnormals_array, m->indexes, m->numindexes, false);
|
||||
}
|
||||
|
||||
void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v, qboolean calcnorms)
|
||||
void QDECL Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v, qboolean calcnorms)
|
||||
{
|
||||
int i;
|
||||
float f;
|
||||
|
@ -352,7 +352,7 @@ static void PSKGenMatrix(float x, float y, float z, float qx, float qy, float qz
|
|||
#endif
|
||||
|
||||
/*transforms some skeletal vecV_t values*/
|
||||
static void Alias_TransformVerticies_V(const float *bonepose, int vertcount, qbyte *bidx, float *weights, float *xyzin, float *fte_restrict xyzout)
|
||||
static void Alias_TransformVerticies_V(const float *bonepose, int vertcount, boneidx_t *bidx, float *weights, float *xyzin, float *fte_restrict xyzout)
|
||||
{
|
||||
#if 1
|
||||
int i, j;
|
||||
|
@ -428,7 +428,7 @@ static void Alias_TransformVerticies_V(const float *bonepose, int vertcount, qby
|
|||
}
|
||||
|
||||
/*transforms some skeletal vecV_t values*/
|
||||
static void Alias_TransformVerticies_VN(const float *bonepose, int vertcount, const qbyte *bidx, float *weights,
|
||||
static void Alias_TransformVerticies_VN(const float *bonepose, int vertcount, const boneidx_t *bidx, float *weights,
|
||||
const float *xyzin, float *fte_restrict xyzout,
|
||||
const float *normin, float *fte_restrict normout)
|
||||
{
|
||||
|
@ -472,7 +472,7 @@ static void Alias_TransformVerticies_VN(const float *bonepose, int vertcount, co
|
|||
}
|
||||
|
||||
/*transforms some skeletal vecV_t values*/
|
||||
static void Alias_TransformVerticies_VNST(const float *bonepose, int vertcount, const qbyte *bidx, const float *weights,
|
||||
static void Alias_TransformVerticies_VNST(const float *bonepose, int vertcount, const boneidx_t *bidx, const float *weights,
|
||||
const float *xyzin, float *fte_restrict xyzout,
|
||||
const float *normin, float *fte_restrict normout,
|
||||
const float *sdirin, float *fte_restrict sdirout,
|
||||
|
@ -708,6 +708,8 @@ struct
|
|||
entity_t *ent;
|
||||
|
||||
#ifdef SKELETALMODELS
|
||||
boneidx_t *bonemap; //force the renderer to forget the current entity when this changes
|
||||
float gpubones[MAX_BONES*12]; //temp storage for multi-surface models with too many bones.
|
||||
float boneposebuffer1[MAX_BONES*12];
|
||||
float boneposebuffer2[MAX_BONES*12];
|
||||
skeltype_t bonecachetype;
|
||||
|
@ -1325,7 +1327,7 @@ static const float *Alias_GetBoneInformation(galiasinfo_t *inf, framestate_t *fr
|
|||
|
||||
static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, galiasinfo_t *inf)
|
||||
{
|
||||
qbyte *fte_restrict bidx = inf->ofs_skel_idx[0];
|
||||
boneidx_t *fte_restrict bidx = inf->ofs_skel_idx[0];
|
||||
float *fte_restrict weight = inf->ofs_skel_weight[0];
|
||||
|
||||
if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE)
|
||||
|
@ -1350,7 +1352,7 @@ static void Alias_BuildSkeletalVerts(float *xyzout, framestate_t *framestate, ga
|
|||
{
|
||||
float buffer[MAX_BONES*12];
|
||||
float bufferalt[MAX_BONES*12];
|
||||
qbyte *fte_restrict bidx = inf->ofs_skel_idx[0];
|
||||
boneidx_t *fte_restrict bidx = inf->ofs_skel_idx[0];
|
||||
float *fte_restrict weight = inf->ofs_skel_weight[0];
|
||||
const float *bonepose = Alias_GetBoneInformation(inf, framestate, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES);
|
||||
|
||||
|
@ -1654,11 +1656,11 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
|
|||
usebones = false;
|
||||
else if (inf->ofs_skel_xyz && !inf->ofs_skel_weight)
|
||||
usebones = false;
|
||||
else if (e->fatness || !inf->ofs_skel_idx || inf->numbones > sh_config.max_gpu_bones)
|
||||
else if (e->fatness || !inf->ofs_skel_idx || (!inf->mappedbones && inf->numbones > sh_config.max_gpu_bones))
|
||||
#endif
|
||||
usebones = false;
|
||||
|
||||
if (0)//meshcache.ent == e)
|
||||
if (meshcache.ent == e)
|
||||
{
|
||||
if (meshcache.vertgroup == inf->shares_verts && meshcache.ent == e && usebones == meshcache.usebones)
|
||||
{
|
||||
|
@ -1683,7 +1685,22 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
|
|||
mesh->boneweights = inf->ofs_skel_weight;
|
||||
mesh->bones = meshcache.usebonepose;
|
||||
mesh->numbones = inf->numbones;
|
||||
}
|
||||
#ifndef SERVERONLY
|
||||
if (meshcache.bonemap != inf->bonemap)
|
||||
{
|
||||
meshcache.bonemap = inf->bonemap;
|
||||
BE_SelectEntity(e);
|
||||
}
|
||||
if (inf->mappedbones)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < inf->mappedbones; i++)
|
||||
memcpy(meshcache.gpubones + i*12, meshcache.usebonepose + inf->bonemap[i]*12, sizeof(float)*12);
|
||||
meshcache.vbo.numbones = inf->mappedbones;
|
||||
meshcache.vbo.bones = meshcache.gpubones;
|
||||
}
|
||||
#endif
|
||||
return false; //don't generate the new vertex positions. We still have them all.
|
||||
}
|
||||
if (meshcache.bonegroup != inf->shares_bones)
|
||||
|
@ -2002,6 +2019,21 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
|
|||
mesh->boneweights = inf->ofs_skel_weight;
|
||||
mesh->bones = meshcache.usebonepose;
|
||||
mesh->numbones = inf->numbones;
|
||||
#ifndef SERVERONLY
|
||||
if (meshcache.bonemap != inf->bonemap)
|
||||
{
|
||||
meshcache.bonemap = inf->bonemap;
|
||||
BE_SelectEntity(e);
|
||||
}
|
||||
if (inf->mappedbones)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < inf->mappedbones; i++)
|
||||
memcpy(meshcache.gpubones + i*12, meshcache.usebonepose + inf->bonemap[i]*12, sizeof(float)*12);
|
||||
meshcache.vbo.numbones = inf->mappedbones;
|
||||
meshcache.vbo.bones = meshcache.gpubones;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2779,7 +2811,7 @@ void Mod_DestroyMesh(galiasinfo_t *galias)
|
|||
}
|
||||
|
||||
#ifndef SERVERONLY
|
||||
static void Mod_GenerateMeshVBO(galiasinfo_t *galias)
|
||||
static void Mod_GenerateMeshVBO(model_t *mod, galiasinfo_t *galias)
|
||||
//vec3_t *vc, vec2_t *tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, index_t *idx, int numidx, int numverts)
|
||||
{
|
||||
#ifdef NONSKELETALMODELS
|
||||
|
@ -2838,10 +2870,64 @@ static void Mod_GenerateMeshVBO(galiasinfo_t *galias)
|
|||
BE_VBO_Data(&vboctx, galias->ofs_skel_svect, sizeof(*galias->ofs_skel_svect) * galias->numverts, &galias->vbo_skel_svector);
|
||||
if (galias->ofs_skel_tvect)
|
||||
BE_VBO_Data(&vboctx, galias->ofs_skel_tvect, sizeof(*galias->ofs_skel_tvect) * galias->numverts, &galias->vbo_skel_tvector);
|
||||
if (galias->ofs_skel_idx)
|
||||
BE_VBO_Data(&vboctx, galias->ofs_skel_idx, sizeof(*galias->ofs_skel_idx) * galias->numverts, &galias->vbo_skel_bonenum);
|
||||
if (galias->ofs_skel_weight)
|
||||
BE_VBO_Data(&vboctx, galias->ofs_skel_weight, sizeof(*galias->ofs_skel_weight) * galias->numverts, &galias->vbo_skel_bweight);
|
||||
if (!galias->mappedbones /*&& galias->numbones > sh_config.max_gpu_bones*/ && galias->ofs_skel_idx)
|
||||
{ //if we're using gpu bones, then its possible that we're trying to load a model with more bones than the gpu supports
|
||||
//to work around this (and get performance back), each surface has a gpu->cpu table so that bones not used on a mesh don't cause it to need to use a software fallback
|
||||
qboolean *seen = alloca(sizeof(*seen) * galias->numbones);
|
||||
int j, k;
|
||||
memset(seen, 0, sizeof(*seen) * galias->numbones);
|
||||
for (j = 0; j < galias->numverts; j++)
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
if (galias->ofs_skel_weight[j][k])
|
||||
seen[galias->ofs_skel_idx[j][k]] = true;
|
||||
}
|
||||
|
||||
for (j = 0, k = 0; j < galias->numbones; j++)
|
||||
{
|
||||
if (seen[j])
|
||||
k++;
|
||||
}
|
||||
if (k < sh_config.max_gpu_bones)
|
||||
{ //okay, we can hardware accelerate that.
|
||||
galias->bonemap = ZG_Malloc(&mod->memgroup, sizeof(*galias->bonemap)*sh_config.max_gpu_bones);
|
||||
galias->mappedbones = 0;
|
||||
for (j = 0; j < galias->numbones; j++)
|
||||
{
|
||||
if (seen[j])
|
||||
galias->bonemap[galias->mappedbones++] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (galias->mappedbones)
|
||||
{
|
||||
boneidx_t *remaps = alloca(sizeof(*remaps) * galias->numbones);
|
||||
bone_vec4_t *bones = alloca(sizeof(*bones) * galias->numverts);
|
||||
int j, k;
|
||||
|
||||
//our remap table is gpu->cpu, but we need cpu->gpu here
|
||||
for (j = 0; j < galias->numbones; j++)
|
||||
remaps[j] = 0; //errors.
|
||||
for (j = 0; j < galias->mappedbones; j++)
|
||||
remaps[galias->bonemap[j]] = j;
|
||||
//now remap them all
|
||||
for (j = 0; j < galias->numverts; j++)
|
||||
for (k = 0; k < 4; k++)
|
||||
bones[j][k] = remaps[galias->ofs_skel_idx[j][k]];
|
||||
|
||||
//and we can upload
|
||||
if (galias->ofs_skel_idx)
|
||||
BE_VBO_Data(&vboctx, bones, sizeof(*bones) * galias->numverts, &galias->vbo_skel_bonenum);
|
||||
if (galias->ofs_skel_weight)
|
||||
BE_VBO_Data(&vboctx, galias->ofs_skel_weight, sizeof(*galias->ofs_skel_weight) * galias->numverts, &galias->vbo_skel_bweight);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (galias->ofs_skel_idx)
|
||||
BE_VBO_Data(&vboctx, galias->ofs_skel_idx, sizeof(*galias->ofs_skel_idx) * galias->numverts, &galias->vbo_skel_bonenum);
|
||||
if (galias->ofs_skel_weight)
|
||||
BE_VBO_Data(&vboctx, galias->ofs_skel_weight, sizeof(*galias->ofs_skel_weight) * galias->numverts, &galias->vbo_skel_bweight);
|
||||
}
|
||||
#endif
|
||||
#ifdef NONSKELETALMODELS
|
||||
for (i = 0; i < galias->numanimations; i++)
|
||||
|
@ -2989,7 +3075,7 @@ void Mod_LoadAliasShaders(model_t *mod)
|
|||
{
|
||||
if (numskins < ai->numskins)
|
||||
numskins = ai->numskins;
|
||||
Mod_GenerateMeshVBO(ai); //FIXME: shares verts
|
||||
Mod_GenerateMeshVBO(mod, ai); //FIXME: shares verts
|
||||
}
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
|
@ -5842,7 +5928,7 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
|
||||
vecV_t *skel_xyz;
|
||||
vec3_t *skel_norm, *skel_svect, *skel_tvect;
|
||||
byte_vec4_t *skel_idx;
|
||||
bone_vec4_t *skel_idx;
|
||||
vec4_t *skel_weights;
|
||||
|
||||
/*load the psk*/
|
||||
|
@ -6127,10 +6213,11 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
skel_tvect = ZG_Malloc(&mod->memgroup, sizeof(*skel_tvect) * num_vtxw);
|
||||
skel_idx = ZG_Malloc(&mod->memgroup, sizeof(*skel_idx) * num_vtxw);
|
||||
skel_weights = ZG_Malloc(&mod->memgroup, sizeof(*skel_weights) * num_vtxw);
|
||||
for (j = 0; j < 4; j++)
|
||||
skel_idx[i][j] = ~0;
|
||||
for (i = 0; i < num_vtxw; i++)
|
||||
{
|
||||
float t;
|
||||
*(unsigned int*)skel_idx[i] = ~0;
|
||||
for (j = 0; j < num_rawweights; j++)
|
||||
{
|
||||
if (rawweights[j].pntsindex == vtxw[i].pntsindex)
|
||||
|
@ -6945,7 +7032,7 @@ galisskeletaltransforms_t *IQM_ImportTransforms(int *resultcount, int inverts, f
|
|||
}
|
||||
*/
|
||||
|
||||
static qboolean IQM_ImportArray4B(const qbyte *fte_restrict base, const struct iqmvertexarray *fte_restrict src, byte_vec4_t *fte_restrict out, size_t count, unsigned int maxval)
|
||||
static qboolean IQM_ImportArray4Bone(const qbyte *fte_restrict base, const struct iqmvertexarray *fte_restrict src, bone_vec4_t *fte_restrict out, size_t count, unsigned int maxval)
|
||||
{
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
@ -6953,7 +7040,7 @@ static qboolean IQM_ImportArray4B(const qbyte *fte_restrict base, const struct i
|
|||
unsigned int fmt = LittleLong(src->format);
|
||||
unsigned int offset = LittleLong(src->offset);
|
||||
qboolean invalid = false;
|
||||
maxval = min(256,maxval); //output is bytes.
|
||||
maxval = min(MAX_BONES,maxval); //output is bytes.
|
||||
if (!offset)
|
||||
{
|
||||
sz = 0;
|
||||
|
@ -7195,7 +7282,7 @@ static const void *IQM_FindExtension(const char *buffer, size_t buffersize, cons
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void Mod_CleanWeights(const char *modelname, size_t numverts, vec4_t *oweight, byte_vec4_t *oindex)
|
||||
static void Mod_CleanWeights(const char *modelname, size_t numverts, vec4_t *oweight, bone_vec4_t *oindex)
|
||||
{ //some IQMs lack weight values, apparently.
|
||||
int j, v;
|
||||
qboolean problemfound = false;
|
||||
|
@ -7258,7 +7345,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
vecV_t *opos=NULL;
|
||||
vec3_t *onorm1=NULL, *onorm2=NULL, *onorm3=NULL;
|
||||
vec4_t *oweight=NULL;
|
||||
byte_vec4_t *oindex=NULL;
|
||||
bone_vec4_t *oindex=NULL;
|
||||
float *opose=NULL,*oposebase=NULL;
|
||||
vec2_t *otcoords = NULL;
|
||||
vec4_t *orgbaf = NULL;
|
||||
|
@ -7273,7 +7360,6 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
galiasanimation_t *fgroup=NULL;
|
||||
galiasbone_t *bones = NULL;
|
||||
index_t *idx;
|
||||
float basepose[12 * MAX_BONES];
|
||||
qboolean noweights;
|
||||
frameinfo_t *framegroups;
|
||||
int numgroups;
|
||||
|
@ -7481,10 +7567,10 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
GenMatrixPosQuat3Scale(ijoint[i].translate, ijoint[i].rotate, ijoint[i].scale, mat);
|
||||
|
||||
if (ijoint[i].parent >= 0)
|
||||
Matrix3x4_Multiply(mat, &basepose[ijoint[i].parent*12], &basepose[i*12]);
|
||||
Matrix3x4_Multiply(mat, &oposebase[ijoint[i].parent*12], &oposebase[i*12]);
|
||||
else
|
||||
memcpy(&basepose[i*12], mat, sizeof(mat));
|
||||
Matrix3x4_Invert_Simple(&basepose[i*12], bones[i].inverse);
|
||||
memcpy(&oposebase[i*12], mat, sizeof(mat));
|
||||
Matrix3x4_Invert_Simple(&oposebase[i*12], bones[i].inverse);
|
||||
}
|
||||
|
||||
//pose info (anim)
|
||||
|
@ -7526,10 +7612,10 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
GenMatrixPosQuat4Scale(ijoint[i].translate, ijoint[i].rotate, ijoint[i].scale, mat);
|
||||
|
||||
if (ijoint[i].parent >= 0)
|
||||
Matrix3x4_Multiply(mat, &basepose[ijoint[i].parent*12], &basepose[i*12]);
|
||||
Matrix3x4_Multiply(mat, &oposebase[ijoint[i].parent*12], &oposebase[i*12]);
|
||||
else
|
||||
memcpy(&basepose[i*12], mat, sizeof(mat));
|
||||
Matrix3x4_Invert_Simple(&basepose[i*12], bones[i].inverse);
|
||||
memcpy(&oposebase[i*12], mat, sizeof(mat));
|
||||
Matrix3x4_Invert_Simple(&oposebase[i*12], bones[i].inverse);
|
||||
}
|
||||
|
||||
//pose info (anim)
|
||||
|
@ -7552,8 +7638,6 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
}
|
||||
}
|
||||
}
|
||||
//basepose
|
||||
memcpy(oposebase, basepose, sizeof(float)*12 * h->num_joints);
|
||||
|
||||
//now generate the animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
|
@ -7724,7 +7808,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
gai[i-1].nextsurf = NULL;
|
||||
if (!noweights)
|
||||
{
|
||||
if (!IQM_ImportArray4B(buffer, &vbone, oindex, h->num_vertexes, h->num_joints))
|
||||
if (!IQM_ImportArray4Bone(buffer, &vbone, oindex, h->num_vertexes, h->num_joints))
|
||||
Con_DPrintf(CON_WARNING "Invalid bone indexes detected inside %s\n", mod->name);
|
||||
IQM_ImportArrayF(buffer, &vweight, (float*)oweight, 4, h->num_vertexes, defaultweight);
|
||||
Mod_CleanWeights(mod->name, h->num_vertexes, oweight, oindex);
|
||||
|
|
|
@ -170,8 +170,8 @@ typedef struct galiasinfo_s
|
|||
struct galiasinfo_s *nextsurf;
|
||||
|
||||
#ifdef SKELETALMODELS
|
||||
// int *bonemap; //some models are horribly complicated, this provides a gpubone->cpubone table, reducing the number of gpu bones needed on a per-mesh basis.
|
||||
// int mappedbones;
|
||||
boneidx_t *bonemap; //filled in automatically if our mesh has more gpu bones than we can support
|
||||
unsigned int mappedbones;
|
||||
|
||||
float *baseframeofs; /*non-heirachical*/
|
||||
int numbones;
|
||||
|
@ -181,7 +181,7 @@ typedef struct galiasinfo_s
|
|||
vec3_t *ofs_skel_norm;
|
||||
vec3_t *ofs_skel_svect;
|
||||
vec3_t *ofs_skel_tvect;
|
||||
byte_vec4_t *ofs_skel_idx;
|
||||
bone_vec4_t *ofs_skel_idx;
|
||||
vec4_t *ofs_skel_weight;
|
||||
|
||||
vboarray_t vbo_skel_verts;
|
||||
|
@ -234,8 +234,8 @@ typedef struct modplugfuncs_s
|
|||
void *reserved2;
|
||||
image_t *(QDECL *GetTexture)(const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt);
|
||||
vfsfile_t *(QDECL *OpenVFS)(const char *filename, const char *mode, enum fs_relative relativeto);
|
||||
void *unused3;
|
||||
void *unused4;
|
||||
void (QDECL *AccumulateTextureVectors)(vecV_t *const vc, vec2_t *const tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, const index_t *idx, int numidx, qboolean calcnorms);
|
||||
void (QDECL *NormaliseTextureVectors)(vec3_t *n, vec3_t *s, vec3_t *t, int v, qboolean calcnorms);
|
||||
void *unused5;
|
||||
void *unused6;
|
||||
void *unused7;
|
||||
|
@ -263,9 +263,9 @@ qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **nam
|
|||
|
||||
void Mod_DoCRC(model_t *mod, char *buffer, int buffersize);
|
||||
|
||||
void Mod_AccumulateTextureVectors(vecV_t *const vc, vec2_t *const tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, const index_t *idx, int numidx, qboolean calcnorms);
|
||||
void QDECL Mod_AccumulateTextureVectors(vecV_t *const vc, vec2_t *const tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, const index_t *idx, int numidx, qboolean calcnorms);
|
||||
void Mod_AccumulateMeshTextureVectors(mesh_t *mesh);
|
||||
void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v, qboolean calcnorms);
|
||||
void QDECL Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v, qboolean calcnorms);
|
||||
void R_Generate_Mesh_ST_Vectors(mesh_t *mesh);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -5209,6 +5209,40 @@ qboolean COM_HasWork(void)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
void COM_InsertWork(wgroup_t tg, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
struct com_work_s *work;
|
||||
|
||||
if (tg >= WG_COUNT)
|
||||
return;
|
||||
|
||||
//no worker there, just do it immediately on this thread instead of pushing it to the worker.
|
||||
if (!com_liveworkers[tg] || (tg!=WG_MAIN && com_workererror))
|
||||
{
|
||||
func(ctx, data, a, b);
|
||||
return;
|
||||
}
|
||||
|
||||
//build the work
|
||||
work = Z_Malloc(sizeof(*work));
|
||||
work->func = func;
|
||||
work->ctx = ctx;
|
||||
work->data = data;
|
||||
work->a = a;
|
||||
work->b = b;
|
||||
|
||||
//queue it (fifo)
|
||||
Sys_LockConditional(com_workercondition[tg]);
|
||||
work->next = com_work_head[tg];
|
||||
if (!com_work_tail[tg])
|
||||
com_work_tail[tg] = work;
|
||||
com_work_head[tg] = work;
|
||||
|
||||
// Sys_Printf("%x: Queued work %p (%s)\n", thread, work->ctx, work->ctx?(char*)work->ctx:"?");
|
||||
|
||||
Sys_ConditionSignal(com_workercondition[tg]);
|
||||
Sys_UnlockConditional(com_workercondition[tg]);
|
||||
}
|
||||
void COM_AddWork(wgroup_t tg, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
struct com_work_s *work;
|
||||
|
@ -6068,6 +6102,26 @@ void InfoSync_Add(infosync_t *sync, void *context, const char *name)
|
|||
sync->keys[k].syncpos = 0;
|
||||
}
|
||||
|
||||
static qboolean InfoBuf_NeedsEncoding(const char *str, size_t size)
|
||||
{
|
||||
const char *c, *e = str+size;
|
||||
for (c = str; c < e; c++)
|
||||
{
|
||||
switch((unsigned char)*c)
|
||||
{
|
||||
case 255: //invalid for vanilla qw, and also used for special encoding
|
||||
case '\\': //abiguity with end-of-token
|
||||
case '\"': //parsing often sends these enclosed in quotes
|
||||
case '\n': //REALLY screws up parsing
|
||||
case '\r': //generally bad form
|
||||
case 0: //are we really doing this?
|
||||
case '$': //a number of engines like expanding things inside quotes. make sure that cannot ever happen.
|
||||
case ';': //in case someone manages to break out of quotes
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
qboolean InfoBuf_FindKey (infobuf_t *info, const char *key, size_t *idx)
|
||||
{
|
||||
size_t k;
|
||||
|
@ -6106,14 +6160,18 @@ char *InfoBuf_ValueForKey (infobuf_t *info, const char *key) //not to be used wi
|
|||
valueindex = (valueindex+1)&3;
|
||||
return InfoBuf_ReadKey(info, key, value[valueindex], sizeof(value[valueindex]));
|
||||
}
|
||||
const char *InfoBuf_BlobForKey (infobuf_t *info, const char *key, size_t *blobsize) //obtains a direct pointer to temp memory
|
||||
const char *InfoBuf_BlobForKey (infobuf_t *info, const char *key, size_t *blobsize, qboolean *large) //obtains a direct pointer to temp memory
|
||||
{
|
||||
size_t k;
|
||||
if (InfoBuf_FindKey(info, key, &k) && !info->keys[k].partial)
|
||||
{
|
||||
if (large)
|
||||
*large = info->keys[k].large;
|
||||
*blobsize = info->keys[k].size;
|
||||
return info->keys[k].value;
|
||||
}
|
||||
if (large)
|
||||
*large = InfoBuf_NeedsEncoding(key, sizeof(key));
|
||||
*blobsize = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -6169,26 +6227,25 @@ char *InfoBuf_DecodeString(const char *instart, const char *inend, size_t *sz)
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static qboolean InfoBuf_IsLarge(struct infokey_s *key)
|
||||
{
|
||||
size_t namesize;
|
||||
if (key->partial)
|
||||
return true;
|
||||
//detect invalid keys/values
|
||||
//\\ makes parsing really really messy and isn't supported by most clients (although we could do it anyway)
|
||||
//\" requires string escapes, again compat issues.
|
||||
//0xff bugs out vanilla.
|
||||
//nulls are bad, too...
|
||||
if (strchr(key->name, '\\') || strchr(key->name, '\"') || strchr(key->name, 0xff))
|
||||
return true;
|
||||
if (strchr(key->value, '\\') || strchr(key->value, '\"') || strchr(key->value, 0xff) || strlen(key->value) != key->size)
|
||||
return true;
|
||||
|
||||
if (key->size >= 64)
|
||||
return true; //key length limits is a thing in vanilla qw.
|
||||
if (strlen(key->name) >= 64)
|
||||
return true; //value length limits is a thing in vanilla qw.
|
||||
//note that qw reads values up to 512, but only sets them up to 64 bytes...
|
||||
//probably just so that people don't spot buffer overflows so easily.
|
||||
namesize = strlen(key->name);
|
||||
if (namesize >= 64)
|
||||
return true; //key length limits is a thing in vanilla qw.
|
||||
|
||||
if (InfoBuf_NeedsEncoding(key->name, namesize))
|
||||
return true;
|
||||
if (InfoBuf_NeedsEncoding(key->value, key->size))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
//like InfoBuf_SetStarBlobKey, but understands partials.
|
||||
|
@ -6423,24 +6480,7 @@ static qboolean InfoBuf_EncodeString_Internal(const char *n, size_t s, char *out
|
|||
{
|
||||
size_t r = 0;
|
||||
const char *c;
|
||||
for (c = n; c < n+s; c++)
|
||||
{
|
||||
if (*c == (char)255 && c == n)
|
||||
break;
|
||||
if (*c == '\\') //abiguity with end-of-token
|
||||
break;
|
||||
if (*c == '\"') //parsing often sends these enclosed in quotes
|
||||
break;
|
||||
if (*c == '\n' || *c == '\r') //generally bad form
|
||||
break;
|
||||
if (*c == 0) //are we really doing this?
|
||||
break;
|
||||
if (*c == '$') //a number of engines like expanding things inside quotes. make sure that cannot ever happen.
|
||||
break;
|
||||
if (*c == ';') //in case someone manages to break out of quotes
|
||||
break;
|
||||
}
|
||||
if (c != n+s)
|
||||
if (InfoBuf_NeedsEncoding(n, s))
|
||||
{
|
||||
unsigned int base64_cur = 0;
|
||||
unsigned int base64_bits = 0;
|
||||
|
|
|
@ -785,7 +785,7 @@ extern const char *basicuserinfos[]; //note: has a leading *
|
|||
extern const char *privateuserinfos[]; //key names that are not broadcast from the server
|
||||
qboolean InfoBuf_FindKey (infobuf_t *info, const char *key, size_t *idx);
|
||||
const char *InfoBuf_KeyForNumber (infobuf_t *info, int num);
|
||||
const char *InfoBuf_BlobForKey (infobuf_t *info, const char *key, size_t *blobsize);
|
||||
const char *InfoBuf_BlobForKey (infobuf_t *info, const char *key, size_t *blobsize, qboolean *large);
|
||||
char *InfoBuf_ReadKey (infobuf_t *info, const char *key, char *outbuf, size_t outsize);
|
||||
char *InfoBuf_ValueForKey (infobuf_t *info, const char *key);
|
||||
qboolean InfoBuf_RemoveKey (infobuf_t *info, const char *key);
|
||||
|
|
|
@ -314,6 +314,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define svcfte_updateentities 86
|
||||
#define svcfte_brushedit 87 // networked brush editing, paired with clcfte_brushedit.
|
||||
#define svcfte_updateseats 88 // byte count, byte playernum[count]
|
||||
#define svcfte_setinfoblob 89 // [8] 1-based index [string] key [32] isfinal<<31|offset [16] chunksize [chunksize] data
|
||||
|
||||
|
||||
//fitz svcs
|
||||
|
|
|
@ -212,7 +212,7 @@ void *Z_Malloc(int size)
|
|||
}
|
||||
#endif
|
||||
|
||||
void Z_StrCat(char **ptr, char *append)
|
||||
void Z_StrCat(char **ptr, const char *append)
|
||||
{
|
||||
size_t oldlen = *ptr?strlen(*ptr):0;
|
||||
size_t newlen = strlen(append);
|
||||
|
|
|
@ -133,7 +133,7 @@ void ZG_FreeGroup(zonegroup_t *ctx);
|
|||
#endif
|
||||
#define Z_StrDup(s) strcpy(Z_Malloc(strlen(s)+1), s)
|
||||
|
||||
void Z_StrCat(char **ptr, char *append);
|
||||
void Z_StrCat(char **ptr, const char *append);
|
||||
|
||||
/*
|
||||
void *Hunk_Alloc (int size); // returns 0 filled memory
|
||||
|
|
|
@ -769,7 +769,7 @@ static void BE_ApplyAttributes(unsigned int bitstochange, unsigned int bitstoend
|
|||
continue;
|
||||
}
|
||||
GL_SelectVBO(shaderstate.sourcevbo->bonenums.gl.vbo);
|
||||
qglVertexAttribPointer(VATTR_BONENUMS, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, shaderstate.sourcevbo->bonenums.gl.addr);
|
||||
qglVertexAttribPointer(VATTR_BONENUMS, 4, GL_BONE_INDEX_TYPE, GL_FALSE, 0, shaderstate.sourcevbo->bonenums.gl.addr);
|
||||
break;
|
||||
case VATTR_BONEWEIGHTS:
|
||||
if (!shaderstate.sourcevbo->boneweights.gl.vbo && !shaderstate.sourcevbo->boneweights.gl.addr)
|
||||
|
@ -1418,12 +1418,12 @@ static float *FTableForFunc ( unsigned int func )
|
|||
}
|
||||
}
|
||||
|
||||
void Shader_LightPass(const char *shortname, shader_t *s, const void *args)
|
||||
void Shader_LightPass(struct shaderparsestate_s *ps, const char *shortname, const void *args)
|
||||
{
|
||||
char shadertext[8192*2];
|
||||
extern cvar_t r_drawflat;
|
||||
sprintf(shadertext, LIGHTPASS_SHADER, (r_lightmap.ival||r_drawflat.ival)?"#FLAT=1.0":"");
|
||||
Shader_DefaultScript(shortname, s, shadertext);
|
||||
Shader_DefaultScript(ps, shortname, shadertext);
|
||||
}
|
||||
|
||||
void GenerateFogTexture(texid_t *tex, float density, float zscale)
|
||||
|
@ -3404,6 +3404,9 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu
|
|||
unsigned int ph;
|
||||
const shaderprogparm_t *p;
|
||||
|
||||
if (perm->factorsuniform != -1)
|
||||
qglUniform4fvARB(perm->factorsuniform, countof(shaderstate.curshader->factors), shaderstate.curshader->factors[0]);
|
||||
|
||||
/*don't bother setting it if the ent properties are unchanged (but do if the mesh changed)*/
|
||||
if (entunchanged)
|
||||
return;
|
||||
|
|
|
@ -54,7 +54,23 @@ typedef enum {
|
|||
SHADER_SORT_COUNT
|
||||
} shadersort_t;
|
||||
|
||||
#ifdef FTE_TARGET_WEB
|
||||
#define MAX_BONES 256
|
||||
#else
|
||||
#define MAX_BONES 256 //Note: there's lots of bone data allocated on the stack, so don't bump recklessly.
|
||||
#endif
|
||||
#if MAX_BONES>65536
|
||||
#define GL_BONE_INDEX_TYPE GL_UNSIGNED_INT
|
||||
typedef unsigned int boneidx_t;
|
||||
#elif MAX_BONES>256
|
||||
#define GL_BONE_INDEX_TYPE GL_UNSIGNED_SHORT
|
||||
typedef unsigned short boneidx_t;
|
||||
#else
|
||||
#define GL_BONE_INDEX_TYPE GL_UNSIGNED_BYTE
|
||||
typedef unsigned char boneidx_t;
|
||||
#endif
|
||||
typedef boneidx_t bone_vec4_t[4];
|
||||
|
||||
struct doll_s;
|
||||
void rag_uninstanciateall(void);
|
||||
void rag_flushdolls(qboolean force);
|
||||
|
@ -102,7 +118,7 @@ typedef struct mesh_s
|
|||
qboolean istrifan; /*if its a fan/poly/single quad (permits optimisations)*/
|
||||
const float *bones;
|
||||
int numbones;
|
||||
byte_vec4_t *bonenums;
|
||||
bone_vec4_t *bonenums;
|
||||
vec4_t *boneweights;
|
||||
} mesh_t;
|
||||
|
||||
|
@ -1040,6 +1056,7 @@ typedef struct model_s
|
|||
//
|
||||
void *meshinfo; //data allocated within the memgroup allocations, will be nulled out when the model is flushed
|
||||
zonegroup_t memgroup;
|
||||
int camerabone; //the 1-based bone index that the camera should be attached to (for gltf rather than anything else)
|
||||
} model_t;
|
||||
|
||||
#define MDLF_EMITREPLACE 0x0001 // particle effect engulphs model (don't draw)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1404,6 +1404,16 @@ static const char *glsl_hdrs[] =
|
|||
// "#define s_deluxmap3 s_deluxemap3\n"
|
||||
#endif
|
||||
#endif
|
||||
"#if defined(ORM) || defined(SG)\n"
|
||||
"uniform vec4 factors[3];\n"
|
||||
"#define factor_base factors[0]\n"
|
||||
"#define factor_spec factors[1]\n"
|
||||
"#define factor_emit factors[2]\n"
|
||||
"#else\n"
|
||||
"#define factor_base vec4(1.0)\n"
|
||||
"#define factor_spec vec4(1.0)\n"
|
||||
"#define factor_emit vec4(1.0)\n"
|
||||
"#endif\n"
|
||||
"#ifdef USEUBOS\n"
|
||||
"layout(std140) uniform u_lightinfo\n"
|
||||
"{"
|
||||
|
@ -1819,6 +1829,67 @@ static const char *glsl_hdrs[] =
|
|||
"#endif\n"
|
||||
"}\n"
|
||||
,
|
||||
|
||||
"sys/pbr.h",
|
||||
//ripped from the gltf webgl demo.
|
||||
//https://github.com/KhronosGroup/glTF-WebGL-PBR/blob/master/shaders/pbr-frag.glsl
|
||||
//because most of this maths is gibberish, especially the odd magic number.
|
||||
"#ifdef PBR\n"
|
||||
"const float PI = 3.141592653589793;\n"
|
||||
"vec3 diffuse(vec3 diffuseColor)\n" //Basic Lambertian diffuse
|
||||
"{\n"
|
||||
"return diffuseColor / PI;\n"
|
||||
"}\n"
|
||||
"vec3 specularReflection(vec3 reflectance0, vec3 reflectance90, float VdotH)\n"
|
||||
"{\n"
|
||||
"return reflectance0 + (reflectance90 - reflectance0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n"
|
||||
"}\n"
|
||||
"float geometricOcclusion(float NdotL, float NdotV, float r)\n"
|
||||
"{\n"
|
||||
"float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));\n"
|
||||
"float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));\n"
|
||||
"return attenuationL * attenuationV;\n"
|
||||
"}\n"
|
||||
"float microfacetDistribution(float alphaRoughness, float NdotH)\n" //Trowbridge-Reitz
|
||||
"{\n"
|
||||
"float roughnessSq = alphaRoughness * alphaRoughness;\n"
|
||||
"float f = (NdotH * roughnessSq - NdotH) * NdotH + 1.0;\n"
|
||||
"return roughnessSq / (PI * f * f);\n"
|
||||
"}\n"
|
||||
"vec3 DoPBR(vec3 n, vec3 v, vec3 l, float perceptualRoughness, vec3 diffuseColor, vec3 specularColor, vec3 scales)\n"
|
||||
"{\n"
|
||||
// Compute reflectance.
|
||||
"float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n"
|
||||
"float alphaRoughness = perceptualRoughness * perceptualRoughness;\n"
|
||||
|
||||
// For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
|
||||
// For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
|
||||
"float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n"
|
||||
"vec3 specularEnvironmentR0 = specularColor.rgb;\n"
|
||||
"vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;\n"
|
||||
|
||||
"vec3 h = normalize(l+v);\n" // Half vector between both l and v
|
||||
"vec3 reflection = -normalize(reflect(v, n));\n"
|
||||
|
||||
"float NdotL = clamp(dot(n, l), 0.001, 1.0);\n"
|
||||
"float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);\n"
|
||||
"float NdotH = clamp(dot(n, h), 0.0, 1.0);\n"
|
||||
"float LdotH = clamp(dot(l, h), 0.0, 1.0);\n"
|
||||
"float VdotH = clamp(dot(v, h), 0.0, 1.0);\n"
|
||||
|
||||
// Calculate the shading terms for the microfacet specular shading model
|
||||
"vec3 F = specularReflection(specularEnvironmentR0, specularEnvironmentR90, VdotH);\n"
|
||||
"float G = geometricOcclusion(NdotL, NdotV, alphaRoughness);\n"
|
||||
"float D = microfacetDistribution(alphaRoughness, NdotH);\n"
|
||||
|
||||
// Calculation of analytical lighting contribution
|
||||
"vec3 diffuseContrib = (1.0 - F) * diffuse(diffuseColor) * scales.y;\n"
|
||||
"vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV) * scales.z;\n"
|
||||
// Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
|
||||
"return NdotL * (diffuseContrib + specContrib);\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
,
|
||||
"sys/pcf.h",
|
||||
//!!cvardf r_glsl_pcf
|
||||
"#ifndef PCF\n"
|
||||
|
@ -2792,6 +2863,8 @@ static void GLSlang_ProgAutoFields(program_t *prog, struct programpermu_s *pp, c
|
|||
pp->numparms = 0;
|
||||
pp->parm = NULL;
|
||||
|
||||
pp->factorsuniform = qglGetUniformLocationARB(pp->h.glsl.handle, "factors");
|
||||
|
||||
for (i = 0; shader_unif_names[i].name; i++)
|
||||
{
|
||||
uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, shader_unif_names[i].name);
|
||||
|
|
|
@ -2828,6 +2828,9 @@ static void GetEvent(void)
|
|||
break;
|
||||
|
||||
case FocusIn:
|
||||
//don't care about it if its just someone wiggling the mouse
|
||||
if (event.xfocus.detail == NotifyPointer)
|
||||
break;
|
||||
//activeapp is if the game window is focused
|
||||
vid.activeapp = true;
|
||||
ClearAllStates(); //just in case.
|
||||
|
@ -2848,6 +2851,9 @@ static void GetEvent(void)
|
|||
// x11.pXUnmapWindow(vid_dpy, vid_decoywindow);
|
||||
break;
|
||||
case FocusOut:
|
||||
//don't care about it if its just someone wiggling the mouse
|
||||
if (event.xfocus.detail == NotifyPointer)
|
||||
break;
|
||||
//if we're already active, the decoy window shouldn't be focused anyway.
|
||||
if (event.xfocus.window == vid_window)
|
||||
x11.ime_shown = -1;
|
||||
|
|
|
@ -2958,10 +2958,16 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"!!cvardf r_tessellation_level=5\n"
|
||||
"!!samps !EIGHTBIT diffuse normalmap specular fullbright upper lower reflectmask reflectcube\n"
|
||||
"!!samps =EIGHTBIT paletted 1\n"
|
||||
//!!permu VC -- adds rgba vertex colour multipliers
|
||||
//!!permu SPECULAR -- auto-added when gl_specular>0
|
||||
//!!permu OFFSETMAPPING -- auto-added when r_glsl_offsetmapping is set
|
||||
//!!permu NONORMALS -- states that there's no normals available, which affects lighting.
|
||||
//!!permu VC // adds rgba vertex colour multipliers
|
||||
//!!permu SPECULAR // auto-added when gl_specular>0
|
||||
//!!permu OFFSETMAPPING // auto-added when r_glsl_offsetmapping is set
|
||||
//!!permu NONORMALS // states that there's no normals available, which affects lighting.
|
||||
//!!permu ORM // specularmap is r:Occlusion, g:Roughness, b:Metalness
|
||||
//!!permu SG // specularmap is rgb:F0, a:Roughness (instead of exponent)
|
||||
//!!permu PBR // an attempt at pbr logic (enabled from ORM or SG)
|
||||
//!!permu NOOCCLUDE // ignores the use of ORM's occlusion... yeah, stupid.
|
||||
//!!permu EIGHTBIT // uses software-style paletted colourmap lookups
|
||||
//!!permu ALPHATEST // if defined, this is the required alpha level (more versatile than doing it at the q3shader level)
|
||||
|
||||
"#include \"sys/defs.h\"\n"
|
||||
|
||||
|
@ -2975,6 +2981,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"#define affine\n"
|
||||
"#endif\n"
|
||||
|
||||
"#if defined(ORM) || defined(SG)\n"
|
||||
"#define PBR\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef NONORMALS //lots of things need normals to work properly. make sure nothing breaks simply because they added an extra texture.\n"
|
||||
"#undef BUMP\n"
|
||||
|
@ -2986,7 +2995,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
|
||||
|
||||
|
||||
|
||||
"#ifdef VERTEX_SHADER\n"
|
||||
"#include \"sys/skeletal.h\"\n"
|
||||
|
||||
|
@ -2995,7 +3003,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n"
|
||||
"varying vec3 eyevector;\n"
|
||||
"#endif\n"
|
||||
"#ifdef REFLECTCUBEMASK\n"
|
||||
"#if defined(PBR)||defined(REFLECTCUBEMASK)\n"
|
||||
"varying mat3 invsurface;\n"
|
||||
"#endif\n"
|
||||
"#ifdef TESS\n"
|
||||
|
@ -3015,22 +3023,28 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"vec3 n, s, t, w;\n"
|
||||
"gl_Position = skeletaltransform_wnst(w,n,s,t);\n"
|
||||
"n = normalize(n);\n"
|
||||
"s = normalize(s);\n"
|
||||
"t = normalize(t);\n"
|
||||
"#ifndef PBR\n"
|
||||
"float d = dot(n,e_light_dir);\n"
|
||||
"if (d < 0.0) //vertex shader. this might get ugly, but I don't really want to make it per vertex.\n"
|
||||
"d = 0.0; //this avoids the dark side going below the ambient level.\n"
|
||||
"light.rgb += (d*e_light_mul);\n"
|
||||
"#else\n"
|
||||
"light.rgb = vec3(1.0);\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
|
||||
"#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n"
|
||||
"#if defined(PBR)\n"
|
||||
"eyevector = e_eyepos - w.xyz;\n"
|
||||
"#elif defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n"
|
||||
"vec3 eyeminusvertex = e_eyepos - w.xyz;\n"
|
||||
"eyevector.x = dot(eyeminusvertex, s.xyz);\n"
|
||||
"eyevector.y = dot(eyeminusvertex, t.xyz);\n"
|
||||
"eyevector.z = dot(eyeminusvertex, n.xyz);\n"
|
||||
"#endif\n"
|
||||
"#ifdef REFLECTCUBEMASK\n"
|
||||
"invsurface[0] = s;\n"
|
||||
"invsurface[1] = t;\n"
|
||||
"invsurface[2] = n;\n"
|
||||
"#if defined(PBR) || defined(REFLECTCUBEMASK)\n"
|
||||
"invsurface = mat3(s, t, n);\n"
|
||||
"#endif\n"
|
||||
|
||||
"tc = v_texcoord;\n"
|
||||
|
@ -3183,10 +3197,39 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n"
|
||||
"varying vec3 eyevector;\n"
|
||||
"#endif\n"
|
||||
"#ifdef REFLECTCUBEMASK\n"
|
||||
"#if defined(PBR) || defined(REFLECTCUBEMASK)\n"
|
||||
"varying mat3 invsurface;\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef PBR\n"
|
||||
"#include \"sys/pbr.h\"\n"
|
||||
"#if 0\n"
|
||||
"vec3 getIBLContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection)\n"
|
||||
"{\n"
|
||||
"float mipCount = 9.0; // resolution of 512x512\n"
|
||||
"float lod = (pbrInputs.perceptualRoughness * mipCount);\n"
|
||||
// retrieve a scale and bias to F0. See [1], Figure 3
|
||||
"vec3 brdf = texture2D(u_brdfLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness)).rgb;\n"
|
||||
"vec3 diffuseLight = textureCube(u_DiffuseEnvSampler, n).rgb;\n"
|
||||
|
||||
"#ifdef USE_TEX_LOD\n"
|
||||
"vec3 specularLight = textureCubeLodEXT(u_SpecularEnvSampler, reflection, lod).rgb;\n"
|
||||
"#else\n"
|
||||
"vec3 specularLight = textureCube(u_SpecularEnvSampler, reflection).rgb;\n"
|
||||
"#endif\n"
|
||||
|
||||
"vec3 diffuse = diffuseLight * pbrInputs.diffuseColor;\n"
|
||||
"vec3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y);\n"
|
||||
|
||||
// For presentation, this allows us to disable IBL terms
|
||||
"diffuse *= u_ScaleIBLAmbient.x;\n"
|
||||
"specular *= u_ScaleIBLAmbient.y;\n"
|
||||
|
||||
"return diffuse + specular;\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
|
||||
|
||||
"void main ()\n"
|
||||
"{\n"
|
||||
|
@ -3218,33 +3261,87 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"col.rgb += lc.rgb*e_lowercolour*lc.a;\n"
|
||||
"#endif\n"
|
||||
|
||||
"#if defined(BUMP) && defined(SPECULAR)\n"
|
||||
"vec3 bumps = normalize(vec3(texture2D(s_normalmap, tc)) - 0.5);\n"
|
||||
"vec4 specs = texture2D(s_specular, tc);\n"
|
||||
"col *= factor_base;\n"
|
||||
|
||||
"vec3 halfdir = normalize(normalize(eyevector) + e_light_dir);\n"
|
||||
"float spec = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * specs.a);\n"
|
||||
"col.rgb += FTE_SPECULAR_MULTIPLIER * spec * specs.rgb;\n"
|
||||
"#elif defined(REFLECTCUBEMASK)\n"
|
||||
"vec3 bumps = vec3(0, 0, 1);\n"
|
||||
"#define dielectricSpecular 0.04\n"
|
||||
"#ifdef SPECULAR\n"
|
||||
"vec4 specs = texture2D(s_specular, tc)*factor_spec;\n"
|
||||
"#ifdef ORM\n"
|
||||
"#define occlusion specs.r\n"
|
||||
"#define roughness clamp(specs.g, 0.04, 1.0)\n"
|
||||
"#define metalness specs.b\n"
|
||||
"#define gloss 1.0 //sqrt(1.0-roughness)\n"
|
||||
"#define ambientrgb (specrgb+col.rgb)\n"
|
||||
"vec3 specrgb = mix(vec3(dielectricSpecular), col.rgb, metalness);\n"
|
||||
"col.rgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);\n"
|
||||
"#elif defined(SG) //pbr-style specular+glossiness\n"
|
||||
//occlusion needs to be baked in. :(
|
||||
"#define roughness (1.0-specs.a)\n"
|
||||
"#define gloss (specs.a)\n"
|
||||
"#define specrgb specs.rgb\n"
|
||||
"#define ambientrgb (specs.rgb+col.rgb)\n"
|
||||
"#else //blinn-phong\n"
|
||||
"#define roughness (1.0-specs.a)\n"
|
||||
"#define gloss specs.a\n"
|
||||
"#define specrgb specs.rgb\n"
|
||||
"#define ambientrgb col.rgb\n"
|
||||
"#endif\n"
|
||||
"#else\n"
|
||||
"#define roughness 0.3\n"
|
||||
"#define specrgb 1.0 //vec3(dielectricSpecular)\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef BUMP\n"
|
||||
"#ifdef PBR //to modelspace\n"
|
||||
"vec3 bumps = normalize(invsurface * (texture2D(s_normalmap, tc).rgb*2.0 - 1.0));\n"
|
||||
"#else //stay in tangentspace\n"
|
||||
"vec3 bumps = normalize(vec3(texture2D(s_normalmap, tc)) - 0.5);\n"
|
||||
"#endif\n"
|
||||
"#else\n"
|
||||
"#ifdef PBR //to modelspace\n"
|
||||
"#define bumps normalize(invsurface[2])\n"
|
||||
"#else //tangent space\n"
|
||||
"#define bumps vec3(0.0, 0.0, 1.0)\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef PBR\n"
|
||||
//move everything to model space
|
||||
"col.rgb = DoPBR(bumps, normalize(eyevector), -e_light_dir, roughness, col.rgb, specrgb, vec3(0.0,1.0,1.0))*e_light_mul + e_light_ambient*.25*ambientrgb;\n"
|
||||
"#elif defined(gloss)\n"
|
||||
"vec3 halfdir = normalize(normalize(eyevector) - e_light_dir);\n"
|
||||
"float specmag = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * gloss);\n"
|
||||
"col.rgb += FTE_SPECULAR_MULTIPLIER * specmag * specrgb;\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef REFLECTCUBEMASK\n"
|
||||
"vec3 rtc = reflect(-eyevector, bumps);\n"
|
||||
"#ifndef PBR\n"
|
||||
"rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];\n"
|
||||
"#endif\n"
|
||||
"rtc = (m_model * vec4(rtc.xyz,0.0)).xyz;\n"
|
||||
"col.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;\n"
|
||||
"#endif\n"
|
||||
|
||||
"#if defined(occlusion) && !defined(NOOCCLUDE)\n"
|
||||
"col.rgb *= occlusion;\n"
|
||||
"#endif\n"
|
||||
"col *= light * e_colourident;\n"
|
||||
|
||||
"#ifdef FULLBRIGHT\n"
|
||||
"vec4 fb = texture2D(s_fullbright, tc);\n"
|
||||
// col.rgb = mix(col.rgb, fb.rgb, fb.a);
|
||||
"col.rgb += fb.rgb * fb.a * e_glowmod.rgb;\n"
|
||||
"col.rgb += fb.rgb * fb.a * e_glowmod.rgb * factor_emit.rgb;\n"
|
||||
"#elif defined(PBR)\n"
|
||||
"col.rgb += e_glowmod.rgb * factor_emit.rgb;\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef ALPHATEST\n"
|
||||
"if (!(col.a ALPHATEST))\n"
|
||||
"discard;\n"
|
||||
"#endif\n"
|
||||
|
||||
"gl_FragColor = fog4(col);\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
|
@ -5508,6 +5605,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"!!samps lightmap deluxemap\n"
|
||||
"!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3\n"
|
||||
|
||||
"#if defined(ORM) || defined(SG)\n"
|
||||
"#define PBR\n"
|
||||
"#endif\n"
|
||||
|
||||
"#include \"sys/defs.h\"\n"
|
||||
|
||||
//this is what normally draws all of your walls, even with rtlights disabled
|
||||
|
@ -5551,9 +5652,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"eyevector.z = dot(eyeminusvertex, v_normal.xyz);\n"
|
||||
"#endif\n"
|
||||
"#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE)\n"
|
||||
"invsurface[0] = v_svector;\n"
|
||||
"invsurface[1] = v_tvector;\n"
|
||||
"invsurface[2] = v_normal;\n"
|
||||
"invsurface = mat3(v_svector, v_tvector, v_normal);\n"
|
||||
"#endif\n"
|
||||
"tc = v_texcoord;\n"
|
||||
"#ifdef FLOW\n"
|
||||
|
@ -5723,6 +5822,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"#ifdef FRAGMENT_SHADER\n"
|
||||
"#define s_colourmap s_t0\n"
|
||||
|
||||
"#include \"sys/pbr.h\"\n"
|
||||
|
||||
"#ifdef OFFSETMAPPING\n"
|
||||
"#include \"sys/offsetmapping.h\"\n"
|
||||
"#endif\n"
|
||||
|
@ -5749,12 +5850,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"#endif\n"
|
||||
|
||||
|
||||
//yay, regular texture!
|
||||
"gl_FragColor = texture2D(s_diffuse, tc);\n"
|
||||
//Read the base texture (with EIGHTBIT only alpha is needed)
|
||||
"vec4 col = texture2D(s_diffuse, tc);\n"
|
||||
|
||||
"#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR) || defined(REFLECTCUBEMASK))\n"
|
||||
"vec3 norm = normalize(texture2D(s_normalmap, tc).rgb - 0.5);\n"
|
||||
"#elif defined(SPECULAR) || defined(DELUXE) || defined(REFLECTCUBEMASK)\n"
|
||||
"#elif defined(PBR) || defined(SPECULAR) || defined(DELUXE) || defined(REFLECTCUBEMASK)\n"
|
||||
"vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist.\n"
|
||||
"#endif\n"
|
||||
|
||||
|
@ -5799,61 +5900,89 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"#endif\n"
|
||||
"#endif\n"
|
||||
|
||||
//add in specular, if applicable.
|
||||
// col *= factor_base;
|
||||
"#define dielectricSpecular 0.04\n"
|
||||
"#ifdef SPECULAR\n"
|
||||
"vec4 specs = texture2D(s_specular, tc);\n"
|
||||
"vec4 specs = texture2D(s_specular, tc);//*factor_spec;\n"
|
||||
"#ifdef ORM\n"
|
||||
"#define occlusion specs.r\n"
|
||||
"#define roughness specs.g\n"
|
||||
"#define metalness specs.b\n"
|
||||
"#define gloss (1.0-roughness)\n"
|
||||
"#define ambientrgb (specrgb+col.rgb)\n"
|
||||
"vec3 specrgb = mix(vec3(dielectricSpecular), col.rgb, metalness);\n"
|
||||
"col.rgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);\n"
|
||||
"#elif defined(SG) //pbr-style specular+glossiness\n"
|
||||
//occlusion needs to be baked in. :(
|
||||
"#define roughness (1.0-specs.a)\n"
|
||||
"#define gloss specs.a\n"
|
||||
"#define specrgb specs.rgb\n"
|
||||
"#define ambientrgb (specs.rgb+col.rgb)\n"
|
||||
"#else //blinn-phong\n"
|
||||
"#define roughness (1.0-specs.a)\n"
|
||||
"#define gloss specs.a\n"
|
||||
"#define specrgb specs.rgb\n"
|
||||
"#define ambientrgb col.rgb\n"
|
||||
"#endif\n"
|
||||
"#else\n"
|
||||
"#define roughness 0.3\n"
|
||||
"#define specrgb 1.0 //vec3(dielectricSpecular)\n"
|
||||
"#endif\n"
|
||||
|
||||
//add in specular, if applicable.
|
||||
"#ifdef PBR\n"
|
||||
"col.rgb = DoPBR(norm, normalize(eyevector), deluxe, roughness, col.rgb, specrgb, vec3(0.0,1.0,1.0));//*e_light_mul + e_light_ambient*.25*ambientrgb;\n"
|
||||
"#elif defined(gloss)\n"
|
||||
"vec3 halfdir = normalize(normalize(eyevector) + deluxe); //this norm should be the deluxemap info instead\n"
|
||||
"float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * specs.a);\n"
|
||||
"float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * gloss);\n"
|
||||
"spec *= FTE_SPECULAR_MULTIPLIER;\n"
|
||||
//NOTE: rtlights tend to have a *4 scaler here to over-emphasise the effect because it looks cool.
|
||||
//As not all maps will have deluxemapping, and the double-cos from the light util makes everything far too dark anyway,
|
||||
//we default to something that is not garish when the light value is directly infront of every single pixel.
|
||||
//we can justify this difference due to the rtlight editor etc showing the *4.
|
||||
"gl_FragColor.rgb += spec * specs.rgb;\n"
|
||||
"col.rgb += spec * specrgb;\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef REFLECTCUBEMASK\n"
|
||||
"vec3 rtc = reflect(normalize(-eyevector), norm);\n"
|
||||
"rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];\n"
|
||||
"rtc = (m_model * vec4(rtc.xyz,0.0)).xyz;\n"
|
||||
"gl_FragColor.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;\n"
|
||||
"col.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef EIGHTBIT //FIXME: with this extra flag, half the permutations are redundant.\n"
|
||||
"lightmaps *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1.\n"
|
||||
"float pal = texture2D(s_paletted, tc).r; //the palette index. hopefully not interpolated.\n"
|
||||
"lightmaps -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest\n"
|
||||
"gl_FragColor.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.\n"
|
||||
"gl_FragColor.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.\n"
|
||||
"gl_FragColor.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.\n"
|
||||
"col.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.\n"
|
||||
"col.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.\n"
|
||||
"col.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.\n"
|
||||
"#else\n"
|
||||
//now we have our diffuse+specular terms, modulate by lightmap values.
|
||||
"gl_FragColor.rgb *= lightmaps.rgb;\n"
|
||||
"col.rgb *= lightmaps.rgb;\n"
|
||||
|
||||
//add on the fullbright
|
||||
"#ifdef FULLBRIGHT\n"
|
||||
"gl_FragColor.rgb += texture2D(s_fullbright, tc).rgb;\n"
|
||||
"col.rgb += texture2D(s_fullbright, tc).rgb;\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
|
||||
//entity modifiers
|
||||
"gl_FragColor = gl_FragColor * e_colourident;\n"
|
||||
"col *= e_colourident;\n"
|
||||
|
||||
"#if defined(MASK)\n"
|
||||
"#if defined(MASKLT)\n"
|
||||
"if (gl_FragColor.a < MASK)\n"
|
||||
"if (col.a < MASK)\n"
|
||||
"discard;\n"
|
||||
"#else\n"
|
||||
"if (gl_FragColor.a >= MASK)\n"
|
||||
"if (col.a >= MASK)\n"
|
||||
"discard;\n"
|
||||
"#endif\n"
|
||||
"gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog.\n"
|
||||
"col.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog.\n"
|
||||
"#endif\n"
|
||||
|
||||
//and finally hide it all if we're fogged.
|
||||
"#ifdef FOG\n"
|
||||
"gl_FragColor = fog4(gl_FragColor);\n"
|
||||
"#endif\n"
|
||||
"gl_FragColor = fog4(col);\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
|
||||
|
@ -10935,6 +11064,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"!!samps =PCF shadowmap\n"
|
||||
"!!samps =CUBE projectionmap\n"
|
||||
|
||||
"#if defined(ORM) || defined(SG)\n"
|
||||
"#define PBR\n"
|
||||
"#endif\n"
|
||||
|
||||
"#include \"sys/defs.h\"\n"
|
||||
|
||||
//this is the main shader responsible for realtime dlights.
|
||||
|
@ -10991,6 +11124,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"{\n"
|
||||
"vec3 n, s, t, w;\n"
|
||||
"gl_Position = skeletaltransform_wnst(w,n,s,t);\n"
|
||||
"n = normalize(n);\n"
|
||||
"s = normalize(s);\n"
|
||||
"t = normalize(t);\n"
|
||||
"tcbase = v_texcoord; //pass the texture coords straight through\n"
|
||||
"#ifdef ORTHO\n"
|
||||
"vec3 lightminusvertex = -l_lightdirection;\n"
|
||||
|
@ -11019,9 +11155,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"eyevector.z = dot(eyeminusvertex, n.xyz);\n"
|
||||
"#endif\n"
|
||||
"#ifdef REFLECTCUBEMASK\n"
|
||||
"invsurface[0] = v_svector;\n"
|
||||
"invsurface[1] = v_tvector;\n"
|
||||
"invsurface[2] = v_normal;\n"
|
||||
"invsurface = mat3(v_svector, v_tvector, v_normal);\n"
|
||||
"#endif\n"
|
||||
"#if defined(PCF) || defined(SPOT) || defined(CUBE) || defined(ORTHO)\n"
|
||||
//for texture projections/shadowmapping on dlights
|
||||
|
@ -11151,6 +11285,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"#include \"sys/offsetmapping.h\"\n"
|
||||
"#endif\n"
|
||||
|
||||
"#include \"sys/pbr.h\"\n"
|
||||
|
||||
"void main ()\n"
|
||||
"{\n"
|
||||
"#ifdef ORTHO\n"
|
||||
|
@ -11199,6 +11335,36 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"vec4 specs = texture2D(s_specular, tcbase);\n"
|
||||
"#endif\n"
|
||||
|
||||
"#define dielectricSpecular 0.04\n"
|
||||
"#ifdef SPECULAR\n"
|
||||
"#ifdef ORM //pbr-style occlusion+roughness+metalness\n"
|
||||
"#define occlusion specs.r\n"
|
||||
"#define roughness clamp(specs.g, 0.04, 1.0)\n"
|
||||
"#define metalness specs.b\n"
|
||||
"#define gloss 1.0 //sqrt(1.0-roughness)\n"
|
||||
"#define ambientrgb (specrgb+col.rgb)\n"
|
||||
"vec3 specrgb = mix(vec3(dielectricSpecular), bases.rgb, metalness);\n"
|
||||
"bases.rgb = bases.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);\n"
|
||||
"#elif defined(SG) //pbr-style specular+glossiness\n"
|
||||
//occlusion needs to be baked in. :(
|
||||
"#define roughness (1.0-specs.a)\n"
|
||||
"#define gloss specs.a\n"
|
||||
"#define specrgb specs.rgb\n"
|
||||
"#define ambientrgb (specs.rgb+col.rgb)\n"
|
||||
"#else //blinn-phong\n"
|
||||
"#define roughness (1.0-specs.a)\n"
|
||||
"#define gloss specs.a\n"
|
||||
"#define specrgb specs.rgb\n"
|
||||
"#define ambientrgb col.rgb\n"
|
||||
"#endif\n"
|
||||
"#else\n"
|
||||
"#define roughness 0.3\n"
|
||||
"#define specrgb 1.0 //vec3(dielectricSpecular)\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef PBR\n"
|
||||
"vec3 diff = DoPBR(bumps, normalize(eyevector), normalize(lightvector), roughness, bases.rgb, specrgb, l_lightcolourscale);\n"
|
||||
"#else\n"
|
||||
"vec3 diff;\n"
|
||||
"#ifdef NOBUMP\n"
|
||||
//surface can only support ambient lighting, even for lights that try to avoid it.
|
||||
|
@ -11212,12 +11378,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"diff = bases.rgb * (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(vec3(0.0, 0.0, 1.0), nl), 0.0));\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
|
||||
|
||||
"#ifdef SPECULAR\n"
|
||||
"vec3 halfdir = normalize(normalize(eyevector) + nl);\n"
|
||||
"float spec = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * specs.a)*float(SPECMUL);\n"
|
||||
"diff += l_lightcolourscale.z * spec * specs.rgb;\n"
|
||||
"float spec = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * gloss)*float(SPECMUL);\n"
|
||||
"diff += l_lightcolourscale.z * spec * specrgb;\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef REFLECTCUBEMASK\n"
|
||||
|
@ -11236,11 +11401,15 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
/*2d projection, not used*/
|
||||
// diff *= texture2d(s_projectionmap, shadowcoord);
|
||||
"#endif\n"
|
||||
"#if defined(occlusion) && !defined(NOOCCLUDE)\n"
|
||||
"diff *= occlusion;\n"
|
||||
"#endif\n"
|
||||
"#if defined(VERTEXCOLOURS)\n"
|
||||
"diff *= vc.rgb * vc.a;\n"
|
||||
"#endif\n"
|
||||
|
||||
"gl_FragColor = vec4(fog3additive(diff*colorscale*l_lightcolour), 1.0);\n"
|
||||
"diff *= colorscale*l_lightcolour;\n"
|
||||
"gl_FragColor = vec4(fog3additive(diff), 1.0);\n"
|
||||
"}\n"
|
||||
"#endif\n"
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ lights are then added over the top based upon the diffusemap, bumpmap and specul
|
|||
|
||||
#ifndef SHADER_H
|
||||
#define SHADER_H
|
||||
typedef void (shader_gen_t)(const char *name, shader_t*, const void *args);
|
||||
struct shaderparsestate_s;
|
||||
typedef void (shader_gen_t)(struct shaderparsestate_s *ps, const char *name, const void *args);
|
||||
|
||||
#define SHADER_TMU_MAX 16
|
||||
#define SHADER_PASS_MAX 16
|
||||
|
@ -512,6 +513,9 @@ struct programpermu_s
|
|||
} hlsl;
|
||||
#endif
|
||||
} h;
|
||||
#endif
|
||||
#ifdef GLQUAKE
|
||||
int factorsuniform;
|
||||
#endif
|
||||
unsigned int permutation;
|
||||
unsigned int attrmask;
|
||||
|
@ -675,6 +679,12 @@ struct shader_s
|
|||
|
||||
bucket_t bucket;
|
||||
|
||||
#define MATERIAL_FACTOR_BASE 0
|
||||
#define MATERIAL_FACTOR_SPEC 1
|
||||
#define MATERIAL_FACTOR_EMIT 2
|
||||
#define MATERIAL_FACTOR_COUNT 3
|
||||
vec4_t factors[MATERIAL_FACTOR_COUNT];
|
||||
|
||||
//arranged as a series of vec4s
|
||||
/* struct
|
||||
{
|
||||
|
@ -711,15 +721,17 @@ cin_t *R_ShaderGetCinematic(shader_t *s);
|
|||
cin_t *R_ShaderFindCinematic(const char *name);
|
||||
shader_t *R_ShaderFind(const char *name); //does NOT increase the shader refcount.
|
||||
|
||||
void Shader_DefaultSkin(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultSkinShell(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultBSPQ2(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultWaterShader(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultSkybox(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultCinematic(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultScript(const char *shortname, shader_t *s, const void *args);
|
||||
void Shader_DefaultSkin (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_DefaultSkinShell (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_Default2D (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_DefaultBSPLM (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_DefaultBSPQ1 (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_DefaultBSPQ2 (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_DefaultWaterShader (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_DefaultSkybox (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_DefaultCinematic (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_DefaultScript (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
void Shader_PolygonShader (struct shaderparsestate_s *ps, const char *shortname, const void *args);
|
||||
|
||||
void Shader_ResetRemaps(void); //called on map changes to reset remapped shaders.
|
||||
void Shader_DoReload(void); //called when the shader system dies.
|
||||
|
|
|
@ -381,7 +381,7 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf, int showlocals)
|
|||
return;
|
||||
}
|
||||
|
||||
progfuncs->funcs.debug_trace = -10;
|
||||
progfuncs->funcs.debug_trace = -10; //PR_StringToNative(+via PR_ValueString) has various error conditions that we want to mute instead of causing recursive errors.
|
||||
|
||||
//point this to the function's locals
|
||||
globalbase = (int *)pr_globals + pr_xfunction->parm_start + pr_xfunction->locals;
|
||||
|
@ -413,16 +413,16 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf, int showlocals)
|
|||
{
|
||||
progs = prnum;
|
||||
|
||||
externs->Printf ("<%s>\n", pr_progstate[progs].filename);
|
||||
externs->DPrintf ("<%s>\n", pr_progstate[progs].filename);
|
||||
}
|
||||
if (!f->s_file)
|
||||
externs->Printf ("stripped : %s\n", PR_StringToNative(ppf, f->s_name));
|
||||
externs->Printf ("unknown-file : %s\n", PR_StringToNative(ppf, f->s_name));
|
||||
else
|
||||
{
|
||||
if (pr_progstate[progs].linenums)
|
||||
externs->Printf ("%12s:%i: %s\n", PR_StringToNative(ppf, f->s_file), pr_progstate[progs].linenums[st], PR_StringToNative(ppf, f->s_name));
|
||||
else
|
||||
externs->Printf ("%12s : %s\n", PR_StringToNative(ppf, f->s_file), PR_StringToNative(ppf, f->s_name));
|
||||
externs->Printf ("%12s : %s+%i\n", PR_StringToNative(ppf, f->s_file), PR_StringToNative(ppf, f->s_name), st-f->first_statement);
|
||||
}
|
||||
|
||||
//locals:0 = no locals
|
||||
|
@ -460,7 +460,7 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf, int showlocals)
|
|||
}
|
||||
else
|
||||
{
|
||||
externs->Printf(" %s: %s\n", local->s_name+progfuncs->funcs.stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase+ofs), false));
|
||||
externs->Printf(" %s: %s\n", PR_StringToNative(ppf, local->s_name), PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase+ofs), false));
|
||||
if (local->type == ev_vector)
|
||||
ofs+=2;
|
||||
}
|
||||
|
|
|
@ -6262,7 +6262,7 @@ static void QCBUILTIN PF_sv_serverkeyblob (pubprogfuncs_t *prinst, struct global
|
|||
{
|
||||
size_t blobsize = 0;
|
||||
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
const char *blobvalue = InfoBuf_BlobForKey(&svs.info, key, &blobsize);
|
||||
const char *blobvalue = InfoBuf_BlobForKey(&svs.info, key, &blobsize, NULL);
|
||||
|
||||
if ((prinst->callargc<2) || G_INT(OFS_PARM1) == 0)
|
||||
G_INT(OFS_RETURN) = blobsize; //no pointer to write to, just return the length.
|
||||
|
@ -6302,7 +6302,7 @@ static void QCBUILTIN PF_getlocalinfo (pubprogfuncs_t *prinst, struct globalvars
|
|||
{
|
||||
size_t blobsize = 0;
|
||||
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
const char *blobvalue = InfoBuf_BlobForKey(&svs.localinfo, key, &blobsize);
|
||||
const char *blobvalue = InfoBuf_BlobForKey(&svs.localinfo, key, &blobsize, NULL);
|
||||
|
||||
if ((prinst->callargc<2) || G_INT(OFS_PARM1) == 0)
|
||||
G_INT(OFS_RETURN) = blobsize; //no pointer to write to, just return the length.
|
||||
|
@ -10565,7 +10565,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
|
|||
#ifndef QUAKETC
|
||||
//mvdsv (don't require ebfs usage in qw)
|
||||
{"executecommand", PF_ExecuteCommand, 0, 0, 0, 83, D("void()","Attempt to flush the localcmd buffer NOW. This is unsafe, as many events might cause the map to be purged while still executing qc code."), true},
|
||||
{"mvdtokenize", PF_Tokenize, 0, 0, 0, 84, D("void(string str)",NULL), true},
|
||||
{"mvdtokenize", PF_tokenize_console,0, 0, 0, 84, D("void(string str)",NULL), true},
|
||||
{"mvdargc", PF_ArgC, 0, 0, 0, 85, D("float()",NULL), true},
|
||||
{"mvdargv", PF_ArgV, 0, 0, 0, 86, D("string(float num)",NULL), true},
|
||||
|
||||
|
|
|
@ -562,6 +562,9 @@ typedef struct client_s
|
|||
#define SENDFLAGS_PRESENT 0x80000000u //this entity is present on that client
|
||||
#define SENDFLAGS_REMOVED 0x40000000u //to handle remove packetloss
|
||||
|
||||
#ifndef NOLEGACY
|
||||
char *dlqueue; //name\name delimited list of files to ask the client to download.
|
||||
#endif
|
||||
char downloadfn[MAX_QPATH];
|
||||
vfsfile_t *download; // file being downloaded
|
||||
qofs_t downloadsize; // total bytes
|
||||
|
@ -1313,6 +1316,10 @@ void SV_UpdateToReliableMessages (void);
|
|||
void SV_FlushBroadcasts (void);
|
||||
qboolean SV_CanTrack(client_t *client, int entity);
|
||||
|
||||
#ifndef NOLEGACY
|
||||
void SV_DownloadQueueNext(client_t *client);
|
||||
void SV_DownloadQueueClear(client_t *client);
|
||||
#endif
|
||||
#ifdef NQPROT
|
||||
void SV_DarkPlacesDownloadChunk(client_t *cl, sizebuf_t *msg);
|
||||
#endif
|
||||
|
|
|
@ -117,8 +117,8 @@ extern cvar_t net_enable_dtls;
|
|||
cvar_t sv_reportheartbeats = CVARD("sv_reportheartbeats", "2", "Print a notice each time a heartbeat is sent to a master server. When set to 2, the message will be displayed once.");
|
||||
cvar_t sv_heartbeat_interval = CVARD("sv_heartbeat_interval", "110", "Interval between heartbeats. Low values are abusive, high values may cause NAT/ghost issues.");
|
||||
cvar_t sv_highchars = CVAR("sv_highchars", "1");
|
||||
cvar_t sv_maxrate = CVARCD("sv_maxrate", "50k", CvarPostfixKMG, "This controls the maximum number of bytes any indivual player may receive (when not downloading). The individual user's rate will also be controlled by the user's rate cvar.");
|
||||
cvar_t sv_maxdrate = CVARAFCD("sv_maxdrate", "500k",
|
||||
cvar_t sv_maxrate = CVARCD("sv_maxrate", "50000", CvarPostfixKMG, "This controls the maximum number of bytes any indivual player may receive (when not downloading). The individual user's rate will also be controlled by the user's rate cvar.");
|
||||
cvar_t sv_maxdrate = CVARAFCD("sv_maxdrate", "500000",
|
||||
"sv_maxdownloadrate", 0, CvarPostfixKMG, "This cvar controls the maximum number of bytes sent to each player per second while that player is downloading.\nIf this cvar is set to 0, there will be NO CAP for download rates (if the user's drate is empty/0 too, then expect really fast+abusive downloads that could potentially be considered denial of service attacks)");
|
||||
cvar_t sv_minping = CVARFD("sv_minping", "", CVAR_SERVERINFO, "Simulate fake lag for any players with a ping under the value specified here. Value is in milliseconds.");
|
||||
|
||||
|
@ -619,6 +619,9 @@ void SV_DropClient (client_t *drop)
|
|||
Con_TPrintf ("Client \"%s\" removed\n",drop->name);
|
||||
}
|
||||
|
||||
#ifndef NOLEGACY
|
||||
SV_DownloadQueueClear(drop);
|
||||
#endif
|
||||
if (drop->download)
|
||||
{
|
||||
VFS_CLOSE (drop->download);
|
||||
|
@ -5456,7 +5459,7 @@ into a more C freindly form.
|
|||
*/
|
||||
void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
|
||||
{
|
||||
char *val, *p;
|
||||
const char *val, *p;
|
||||
int i;
|
||||
client_t *client;
|
||||
int dupc = 1;
|
||||
|
@ -5464,6 +5467,8 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
|
|||
#ifdef SVRANKING
|
||||
extern cvar_t rank_filename;
|
||||
#endif
|
||||
size_t blobsize;
|
||||
qboolean large;
|
||||
|
||||
int bottom = atoi(InfoBuf_ValueForKey(&cl->userinfo, "bottomcolor"));
|
||||
|
||||
|
@ -5481,16 +5486,19 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
|
|||
Q_strncpyz (cl->team, val, sizeof(cl->teambuf));
|
||||
|
||||
// name for C code
|
||||
val = InfoBuf_ValueForKey (&cl->userinfo, "name");
|
||||
|
||||
if (cl->protocol != SCP_BAD || *val)
|
||||
val = InfoBuf_BlobForKey (&cl->userinfo, "name", &blobsize, &large);
|
||||
if (!val)
|
||||
val = "";
|
||||
//we block large names here because a) they're unwieldly. b) they might cause players to be invisible to older clients/server browsers/etc.
|
||||
//bots with no name skip the fixup, to avoid default names(they're expected to be given a name eventually, so are allowed to be invisible for now)
|
||||
if (large || (cl->protocol == SCP_BAD && !*val))
|
||||
newname[0] = 0;
|
||||
else
|
||||
{
|
||||
SV_FixupName(val, newname, sizeof(newname));
|
||||
if (strlen(newname) > 40)
|
||||
newname[40] = 0;
|
||||
}
|
||||
else
|
||||
newname[0] = 0;
|
||||
|
||||
deleetstring(basic, newname);
|
||||
if (cl->protocol != SCP_BAD)
|
||||
|
|
|
@ -2786,14 +2786,13 @@ static qboolean SV_SyncInfoBuf(client_t *client)
|
|||
infobuf_t *info = client->infosync.keys[0].context;
|
||||
size_t bloboffset = client->infosync.keys[0].syncpos;
|
||||
//unsigned int seat = info - cls.userinfo;
|
||||
qboolean large;
|
||||
size_t blobsize;
|
||||
const char *blobdata = InfoBuf_BlobForKey(info, key, &blobsize);
|
||||
const char *blobdata = InfoBuf_BlobForKey(info, key, &blobsize, &large);
|
||||
size_t sendsize;
|
||||
size_t bufferspace;
|
||||
|
||||
qboolean final;
|
||||
char enckey[2048];
|
||||
char encval[2048];
|
||||
|
||||
if (client->protocol == SCP_QUAKE2)
|
||||
{ //q2 gamecode is fully responsible for networking this via configstrings.
|
||||
|
@ -2806,36 +2805,17 @@ static qboolean SV_SyncInfoBuf(client_t *client)
|
|||
if (client->netchan.message.cursize >= MAX_BACKBUFLEN/2)
|
||||
return false; //don't bother trying to send anything.
|
||||
|
||||
if (!InfoBuf_EncodeString(key, strlen(key), enckey, sizeof(enckey)))
|
||||
{
|
||||
InfoSync_Remove(&client->infosync, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
sendsize = blobsize - bloboffset;
|
||||
bufferspace = MAX_BACKBUFLEN - client->netchan.message.cursize;
|
||||
bufferspace -= 7 - strlen(enckey) - 2; //extra overhead
|
||||
bufferspace = (bufferspace/4)*3; //encoding overhead
|
||||
sendsize = min(bufferspace, sendsize);
|
||||
final = (bloboffset+sendsize >= blobsize);
|
||||
|
||||
if (!InfoBuf_EncodeString(blobdata+bloboffset, sendsize, encval, sizeof(encval)))
|
||||
{
|
||||
InfoSync_Remove(&client->infosync, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (final && !bloboffset && *enckey != '\xff' && *encval != '\xff')
|
||||
if (!large)
|
||||
{ //vanilla-compatible info.
|
||||
if (ISNQCLIENT(client))
|
||||
{ //except that nq never had any userinfo
|
||||
const char *s;
|
||||
if (info == &svs.info)
|
||||
s = va("//svi \"%s\" \"%s\"\n", enckey, encval);
|
||||
s = va("//svi \"%s\" \"%s\"\n", key, blobdata);
|
||||
else
|
||||
{
|
||||
int playerslot = (client_t*)((char*)info-(char*)&((client_t*)NULL)->userinfo)-svs.clients;
|
||||
s = va("//ui %i \"%s\" \"%s\"\n", playerslot, enckey, encval);
|
||||
s = va("//ui %i \"%s\" \"%s\"\n", playerslot, key, blobdata);
|
||||
}
|
||||
ClientReliableWrite_Begin(client, svc_stufftext, strlen(s)+2);
|
||||
ClientReliableWrite_String(client, s);
|
||||
|
@ -2843,41 +2823,53 @@ static qboolean SV_SyncInfoBuf(client_t *client)
|
|||
else
|
||||
{
|
||||
if (info == &svs.info)
|
||||
ClientReliableWrite_Begin(client, svc_serverinfo, 1+strlen(enckey)+1+strlen(encval)+1);
|
||||
ClientReliableWrite_Begin(client, svc_serverinfo, 1+strlen(key)+1+strlen(blobdata)+1);
|
||||
else
|
||||
{
|
||||
ClientReliableWrite_Begin(client, svc_setinfo, 2+strlen(enckey)+1+strlen(encval)+1);
|
||||
ClientReliableWrite_Begin(client, svc_setinfo, 2+strlen(key)+1+strlen(blobdata)+1);
|
||||
ClientReliableWrite_Byte(client, (client_t*)((char*)info-(char*)&((client_t*)NULL)->userinfo)-svs.clients);
|
||||
}
|
||||
ClientReliableWrite_String(client, enckey);
|
||||
ClientReliableWrite_String(client, encval);
|
||||
ClientReliableWrite_String(client, key);
|
||||
ClientReliableWrite_String(client, blobdata);
|
||||
}
|
||||
}
|
||||
else if (client->fteprotocolextensions2 & PEXT2_INFOBLOBS)
|
||||
{
|
||||
int pl;
|
||||
char enckey[2048];
|
||||
unsigned int pl;
|
||||
if (info == &svs.info)
|
||||
pl = 255; //colourmaps being 1-based with these being 0-based means that only 0-254 are valid players, and 255 is unused, so lets use it for serverinfo blobs.
|
||||
pl = 0; //colourmaps being 1-based with these being 0-based means that only 0-254 are valid players, and 255 is unused, so lets use it for serverinfo blobs.
|
||||
else
|
||||
pl = (client_t*)((char*)info-(char*)&((client_t*)NULL)->userinfo)-svs.clients;
|
||||
pl = 1+((client_t*)((char*)info-(char*)&((client_t*)NULL)->userinfo)-svs.clients);
|
||||
|
||||
ClientReliableWrite_Begin(client, svc_setinfo, 7+strlen(enckey)+1+strlen(encval)+1);
|
||||
ClientReliableWrite_Byte(client, 255); //special meaning to say that this is a partial update
|
||||
ClientReliableWrite_Byte(client, pl);
|
||||
ClientReliableWrite_Long(client, (final?0x80000000:0)|bloboffset);
|
||||
if (!InfoBuf_EncodeString(key, strlen(key), enckey, sizeof(enckey)))
|
||||
{
|
||||
InfoSync_Remove(&client->infosync, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
sendsize = blobsize - bloboffset;
|
||||
bufferspace = MAX_BACKBUFLEN - client->netchan.message.cursize;
|
||||
bufferspace -= 8 - strlen(enckey) - 1; //extra overhead
|
||||
sendsize = min(bufferspace, sendsize);
|
||||
final = (bloboffset+sendsize >= blobsize);
|
||||
|
||||
ClientReliableWrite_Begin(client, svcfte_setinfoblob, 8+strlen(enckey)+1+sendsize);
|
||||
ClientReliableWrite_Byte(client, pl); //special meaning to say that this is a partial update
|
||||
ClientReliableWrite_String(client, enckey);
|
||||
ClientReliableWrite_String(client, encval);
|
||||
}
|
||||
else
|
||||
{ //client can't receive this info, stop trying to send it.
|
||||
InfoSync_Remove(&client->infosync, 0);
|
||||
return true;
|
||||
}
|
||||
ClientReliableWrite_Long(client, (final?0x80000000:0)|bloboffset);
|
||||
ClientReliableWrite_Short(client, sendsize);
|
||||
ClientReliableWrite_SZ(client, blobdata+bloboffset, sendsize);
|
||||
|
||||
if (bloboffset+sendsize == blobsize)
|
||||
InfoSync_Remove(&client->infosync, 0);
|
||||
else
|
||||
client->infosync.keys[0].syncpos += sendsize;
|
||||
if (!final)
|
||||
{
|
||||
client->infosync.keys[0].syncpos += sendsize;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//else client can't receive this info, stop trying to send it.
|
||||
|
||||
InfoSync_Remove(&client->infosync, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2472,6 +2472,10 @@ static void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezf
|
|||
|
||||
|
||||
host_client->downloadstarted = false;
|
||||
|
||||
#ifndef NOLEGACY
|
||||
SV_DownloadQueueNext(host_client);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2551,6 +2555,9 @@ void SV_NextDownload_f (void)
|
|||
VFS_CLOSE (host_client->download);
|
||||
host_client->download = NULL;
|
||||
|
||||
#ifndef NOLEGACY
|
||||
SV_DownloadQueueNext(host_client);
|
||||
#endif
|
||||
}
|
||||
|
||||
void VARGS OutofBandPrintf(netadr_t *where, char *fmt, ...)
|
||||
|
@ -2996,6 +3003,8 @@ qboolean SV_AllowDownload (const char *name)
|
|||
return false;
|
||||
if (*name == '/') //no absolute.
|
||||
return false;
|
||||
if (strchr(name, ':')) //no drives, alternative resources, etc. the filesystem should refuse such a file so this should just be paranoia.
|
||||
return false;
|
||||
if (strchr(name, '\\')) //no windows paths - grow up you lame windows users.
|
||||
return false;
|
||||
|
||||
|
@ -3037,7 +3046,7 @@ qboolean SV_AllowDownload (const char *name)
|
|||
if (Q_strncasecmp(name, "sound/", 6) == 0)
|
||||
return !!allow_download_sounds.value;
|
||||
//particles
|
||||
if (Q_strncasecmp(name, "particles/", 6) == 0)
|
||||
if (Q_strncasecmp(name, "particles/", 10) == 0)
|
||||
return !!allow_download_particles.value;
|
||||
//demos
|
||||
if (Q_strncasecmp(name, "demos/", 6) == 0)
|
||||
|
@ -3290,6 +3299,50 @@ void SV_DownloadSize_f(void)
|
|||
}
|
||||
|
||||
#ifdef MVD_RECORDING
|
||||
|
||||
#ifndef NOLEGACY
|
||||
void SV_DownloadQueueAdd(client_t *client, const char *name)
|
||||
{
|
||||
if (!client->dlqueue)
|
||||
{
|
||||
client->dlqueue = Z_StrDup(name);
|
||||
SV_ClientPrintf (client, PRINT_HIGH, "Using legacy serverside download queue. This is subject to race conditions, be careful.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Z_StrCat(&client->dlqueue, "\\");
|
||||
Z_StrCat(&client->dlqueue, name);
|
||||
}
|
||||
}
|
||||
void SV_DownloadQueueNext(client_t *client)
|
||||
{
|
||||
char buf[MAX_QPATH*2];
|
||||
char *name = client->dlqueue;
|
||||
char *next;
|
||||
if (!name)
|
||||
return;
|
||||
next = strchr(name, '\\');
|
||||
if (next)
|
||||
{
|
||||
host_client->dlqueue = Z_StrDup(next+1);
|
||||
*next = 0;
|
||||
}
|
||||
else
|
||||
client->dlqueue = NULL;
|
||||
|
||||
next = va("download \"%s\"\n", COM_QuotedString(name, buf, sizeof(buf), true));
|
||||
ClientReliableWrite_Begin (client, svc_stufftext, 2+strlen(next));
|
||||
ClientReliableWrite_String (client, next);
|
||||
Z_Free(name);
|
||||
}
|
||||
void SV_DownloadQueueClear(client_t *client)
|
||||
{
|
||||
if (client->dlqueue)
|
||||
Z_Free(client->dlqueue);
|
||||
client->dlqueue = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SV_DemoDownload_f(void)
|
||||
{
|
||||
int arg;
|
||||
|
@ -3306,7 +3359,16 @@ void SV_DemoDownload_f(void)
|
|||
name = Cmd_Argv(1);
|
||||
if (!strcmp(name, "\\") || !Q_strcasecmp(name, "stop") || !Q_strcasecmp(name, "cancel"))
|
||||
{
|
||||
//fte servers don't do download queues, as it is impossible to avoid race conditions with vanilla clients anyway.
|
||||
if (strcmp(name, "\\"))
|
||||
{ //cancel/stop kill any current download too. which is annoying
|
||||
if (host_client->download)
|
||||
VFS_CLOSE (host_client->download);
|
||||
host_client->download = NULL;
|
||||
host_client->downloadstarted = false;
|
||||
}
|
||||
#ifndef NOLEGACY
|
||||
SV_DownloadQueueClear(host_client);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -3339,6 +3401,14 @@ void SV_DemoDownload_f(void)
|
|||
|
||||
if (!mvdname)
|
||||
SV_ClientPrintf (host_client, PRINT_HIGH, "%s is an invalid MVD demonum.\n", name);
|
||||
#ifndef NOLEGACY
|
||||
else if (!(host_client->protocol & PEXT_CHUNKEDDOWNLOADS) || !strncmp(InfoBuf_ValueForKey(&host_client->userinfo, "*client"), "ezQuake", 7))
|
||||
{ //chunked downloads was built around the client being in control (because only it knows which files are needed)
|
||||
//but ezquake never implemented that part
|
||||
SV_DownloadQueueAdd(host_client, va("demos/%s", mvdname));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
const char *s = va("download \"demos/%s\"\n", mvdname);
|
||||
|
@ -3346,6 +3416,10 @@ void SV_DemoDownload_f(void)
|
|||
ClientReliableWrite_String (host_client, s);
|
||||
}
|
||||
}
|
||||
#ifndef NOLEGACY
|
||||
if (!host_client->download)
|
||||
SV_DownloadQueueNext(host_client);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3458,7 +3532,7 @@ void SV_BeginDownload_f(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (!host_client->download)
|
||||
if (!host_client->download && !result)
|
||||
result = -1; //this isn't likely, but hey.
|
||||
|
||||
//handle errors
|
||||
|
@ -3514,6 +3588,7 @@ void SV_BeginDownload_f(void)
|
|||
}
|
||||
if (ISNQCLIENT(host_client))
|
||||
host_client->send_message = true;
|
||||
SV_DownloadQueueNext(host_client);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3588,6 +3663,11 @@ void SV_StopDownload_f(void)
|
|||
SV_ClientPrintf(host_client, PRINT_HIGH, "Can't stop download - not downloading anything\n");
|
||||
|
||||
host_client->downloadstarted = false;
|
||||
|
||||
#ifndef NOLEGACY
|
||||
SV_DownloadQueueNext(host_client);
|
||||
// SV_DownloadQueueClear(host_client);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
@ -18,8 +18,11 @@
|
|||
//!!permu OFFSETMAPPING // auto-added when r_glsl_offsetmapping is set
|
||||
//!!permu NONORMALS // states that there's no normals available, which affects lighting.
|
||||
//!!permu ORM // specularmap is r:Occlusion, g:Roughness, b:Metalness
|
||||
//!!permu F0R // specularmap is rgb:F0, a:Roughness (instead of exponent)
|
||||
//!!permu PBR // an attempt at pbr logic
|
||||
//!!permu SG // specularmap is rgb:F0, a:Roughness (instead of exponent)
|
||||
//!!permu PBR // an attempt at pbr logic (enabled from ORM or SG)
|
||||
//!!permu NOOCCLUDE // ignores the use of ORM's occlusion... yeah, stupid.
|
||||
//!!permu EIGHTBIT // uses software-style paletted colourmap lookups
|
||||
//!!permu ALPHATEST // if defined, this is the required alpha level (more versatile than doing it at the q3shader level)
|
||||
|
||||
#include "sys/defs.h"
|
||||
|
||||
|
@ -33,6 +36,9 @@
|
|||
#define affine
|
||||
#endif
|
||||
|
||||
#if defined(ORM) || defined(SG)
|
||||
#define PBR
|
||||
#endif
|
||||
|
||||
#ifdef NONORMALS //lots of things need normals to work properly. make sure nothing breaks simply because they added an extra texture.
|
||||
#undef BUMP
|
||||
|
@ -44,7 +50,6 @@
|
|||
|
||||
|
||||
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
#include "sys/skeletal.h"
|
||||
|
||||
|
@ -53,7 +58,7 @@ varying vec4 light;
|
|||
#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
varying vec3 eyevector;
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
#if defined(PBR)||defined(REFLECTCUBEMASK)
|
||||
varying mat3 invsurface;
|
||||
#endif
|
||||
#ifdef TESS
|
||||
|
@ -73,22 +78,28 @@ void main ()
|
|||
vec3 n, s, t, w;
|
||||
gl_Position = skeletaltransform_wnst(w,n,s,t);
|
||||
n = normalize(n);
|
||||
float d = dot(n,e_light_dir);
|
||||
if (d < 0.0) //vertex shader. this might get ugly, but I don't really want to make it per vertex.
|
||||
d = 0.0; //this avoids the dark side going below the ambient level.
|
||||
light.rgb += (d*e_light_mul);
|
||||
s = normalize(s);
|
||||
t = normalize(t);
|
||||
#ifndef PBR
|
||||
float d = dot(n,e_light_dir);
|
||||
if (d < 0.0) //vertex shader. this might get ugly, but I don't really want to make it per vertex.
|
||||
d = 0.0; //this avoids the dark side going below the ambient level.
|
||||
light.rgb += (d*e_light_mul);
|
||||
#else
|
||||
light.rgb = vec3(1.0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
#if defined(PBR)
|
||||
eyevector = e_eyepos - w.xyz;
|
||||
#elif defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
vec3 eyeminusvertex = e_eyepos - w.xyz;
|
||||
eyevector.x = dot(eyeminusvertex, s.xyz);
|
||||
eyevector.y = dot(eyeminusvertex, t.xyz);
|
||||
eyevector.z = dot(eyeminusvertex, n.xyz);
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
invsurface[0] = s;
|
||||
invsurface[1] = t;
|
||||
invsurface[2] = n;
|
||||
#if defined(PBR) || defined(REFLECTCUBEMASK)
|
||||
invsurface = mat3(s, t, n);
|
||||
#endif
|
||||
|
||||
tc = v_texcoord;
|
||||
|
@ -241,10 +252,39 @@ varying vec4 light;
|
|||
#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
varying vec3 eyevector;
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
#if defined(PBR) || defined(REFLECTCUBEMASK)
|
||||
varying mat3 invsurface;
|
||||
#endif
|
||||
|
||||
#ifdef PBR
|
||||
#include "sys/pbr.h"
|
||||
#if 0
|
||||
vec3 getIBLContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection)
|
||||
{
|
||||
float mipCount = 9.0; // resolution of 512x512
|
||||
float lod = (pbrInputs.perceptualRoughness * mipCount);
|
||||
// retrieve a scale and bias to F0. See [1], Figure 3
|
||||
vec3 brdf = texture2D(u_brdfLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness)).rgb;
|
||||
vec3 diffuseLight = textureCube(u_DiffuseEnvSampler, n).rgb;
|
||||
|
||||
#ifdef USE_TEX_LOD
|
||||
vec3 specularLight = textureCubeLodEXT(u_SpecularEnvSampler, reflection, lod).rgb;
|
||||
#else
|
||||
vec3 specularLight = textureCube(u_SpecularEnvSampler, reflection).rgb;
|
||||
#endif
|
||||
|
||||
vec3 diffuse = diffuseLight * pbrInputs.diffuseColor;
|
||||
vec3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y);
|
||||
|
||||
// For presentation, this allows us to disable IBL terms
|
||||
diffuse *= u_ScaleIBLAmbient.x;
|
||||
specular *= u_ScaleIBLAmbient.y;
|
||||
|
||||
return diffuse + specular;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
void main ()
|
||||
{
|
||||
|
@ -276,33 +316,87 @@ void main ()
|
|||
col.rgb += lc.rgb*e_lowercolour*lc.a;
|
||||
#endif
|
||||
|
||||
#if defined(BUMP) && defined(SPECULAR)
|
||||
vec3 bumps = normalize(vec3(texture2D(s_normalmap, tc)) - 0.5);
|
||||
vec4 specs = texture2D(s_specular, tc);
|
||||
col *= factor_base;
|
||||
|
||||
vec3 halfdir = normalize(normalize(eyevector) + e_light_dir);
|
||||
float spec = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * specs.a);
|
||||
col.rgb += FTE_SPECULAR_MULTIPLIER * spec * specs.rgb;
|
||||
#elif defined(REFLECTCUBEMASK)
|
||||
vec3 bumps = vec3(0, 0, 1);
|
||||
#define dielectricSpecular 0.04
|
||||
#ifdef SPECULAR
|
||||
vec4 specs = texture2D(s_specular, tc)*factor_spec;
|
||||
#ifdef ORM
|
||||
#define occlusion specs.r
|
||||
#define roughness clamp(specs.g, 0.04, 1.0)
|
||||
#define metalness specs.b
|
||||
#define gloss 1.0 //sqrt(1.0-roughness)
|
||||
#define ambientrgb (specrgb+col.rgb)
|
||||
vec3 specrgb = mix(vec3(dielectricSpecular), col.rgb, metalness);
|
||||
col.rgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);
|
||||
#elif defined(SG) //pbr-style specular+glossiness
|
||||
//occlusion needs to be baked in. :(
|
||||
#define roughness (1.0-specs.a)
|
||||
#define gloss (specs.a)
|
||||
#define specrgb specs.rgb
|
||||
#define ambientrgb (specs.rgb+col.rgb)
|
||||
#else //blinn-phong
|
||||
#define roughness (1.0-specs.a)
|
||||
#define gloss specs.a
|
||||
#define specrgb specs.rgb
|
||||
#define ambientrgb col.rgb
|
||||
#endif
|
||||
#else
|
||||
#define roughness 0.3
|
||||
#define specrgb 1.0 //vec3(dielectricSpecular)
|
||||
#endif
|
||||
|
||||
#ifdef BUMP
|
||||
#ifdef PBR //to modelspace
|
||||
vec3 bumps = normalize(invsurface * (texture2D(s_normalmap, tc).rgb*2.0 - 1.0));
|
||||
#else //stay in tangentspace
|
||||
vec3 bumps = normalize(vec3(texture2D(s_normalmap, tc)) - 0.5);
|
||||
#endif
|
||||
#else
|
||||
#ifdef PBR //to modelspace
|
||||
#define bumps normalize(invsurface[2])
|
||||
#else //tangent space
|
||||
#define bumps vec3(0.0, 0.0, 1.0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PBR
|
||||
//move everything to model space
|
||||
col.rgb = DoPBR(bumps, normalize(eyevector), -e_light_dir, roughness, col.rgb, specrgb, vec3(0.0,1.0,1.0))*e_light_mul + e_light_ambient*.25*ambientrgb;
|
||||
#elif defined(gloss)
|
||||
vec3 halfdir = normalize(normalize(eyevector) - e_light_dir);
|
||||
float specmag = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * gloss);
|
||||
col.rgb += FTE_SPECULAR_MULTIPLIER * specmag * specrgb;
|
||||
#endif
|
||||
|
||||
#ifdef REFLECTCUBEMASK
|
||||
vec3 rtc = reflect(-eyevector, bumps);
|
||||
rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];
|
||||
#ifndef PBR
|
||||
rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];
|
||||
#endif
|
||||
rtc = (m_model * vec4(rtc.xyz,0.0)).xyz;
|
||||
col.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;
|
||||
#endif
|
||||
|
||||
#if defined(occlusion) && !defined(NOOCCLUDE)
|
||||
col.rgb *= occlusion;
|
||||
#endif
|
||||
col *= light * e_colourident;
|
||||
|
||||
#ifdef FULLBRIGHT
|
||||
vec4 fb = texture2D(s_fullbright, tc);
|
||||
// col.rgb = mix(col.rgb, fb.rgb, fb.a);
|
||||
col.rgb += fb.rgb * fb.a * e_glowmod.rgb;
|
||||
col.rgb += fb.rgb * fb.a * e_glowmod.rgb * factor_emit.rgb;
|
||||
#elif defined(PBR)
|
||||
col.rgb += e_glowmod.rgb * factor_emit.rgb;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ALPHATEST
|
||||
if (!(col.a ALPHATEST))
|
||||
discard;
|
||||
#endif
|
||||
|
||||
gl_FragColor = fog4(col);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
!!samps lightmap deluxemap
|
||||
!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3
|
||||
|
||||
#if defined(ORM) || defined(SG)
|
||||
#define PBR
|
||||
#endif
|
||||
|
||||
#include "sys/defs.h"
|
||||
|
||||
//this is what normally draws all of your walls, even with rtlights disabled
|
||||
|
@ -58,9 +62,7 @@ void main ()
|
|||
eyevector.z = dot(eyeminusvertex, v_normal.xyz);
|
||||
#endif
|
||||
#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE)
|
||||
invsurface[0] = v_svector;
|
||||
invsurface[1] = v_tvector;
|
||||
invsurface[2] = v_normal;
|
||||
invsurface = mat3(v_svector, v_tvector, v_normal);
|
||||
#endif
|
||||
tc = v_texcoord;
|
||||
#ifdef FLOW
|
||||
|
@ -230,6 +232,8 @@ void main()
|
|||
#ifdef FRAGMENT_SHADER
|
||||
#define s_colourmap s_t0
|
||||
|
||||
#include "sys/pbr.h"
|
||||
|
||||
#ifdef OFFSETMAPPING
|
||||
#include "sys/offsetmapping.h"
|
||||
#endif
|
||||
|
@ -256,12 +260,12 @@ void main ()
|
|||
#endif
|
||||
|
||||
|
||||
//yay, regular texture!
|
||||
gl_FragColor = texture2D(s_diffuse, tc);
|
||||
//Read the base texture (with EIGHTBIT only alpha is needed)
|
||||
vec4 col = texture2D(s_diffuse, tc);
|
||||
|
||||
#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR) || defined(REFLECTCUBEMASK))
|
||||
vec3 norm = normalize(texture2D(s_normalmap, tc).rgb - 0.5);
|
||||
#elif defined(SPECULAR) || defined(DELUXE) || defined(REFLECTCUBEMASK)
|
||||
#elif defined(PBR) || defined(SPECULAR) || defined(DELUXE) || defined(REFLECTCUBEMASK)
|
||||
vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist.
|
||||
#endif
|
||||
|
||||
|
@ -306,61 +310,89 @@ void main ()
|
|||
#endif
|
||||
#endif
|
||||
|
||||
//add in specular, if applicable.
|
||||
#ifdef SPECULAR
|
||||
vec4 specs = texture2D(s_specular, tc);
|
||||
vec3 halfdir = normalize(normalize(eyevector) + deluxe); //this norm should be the deluxemap info instead
|
||||
float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * specs.a);
|
||||
spec *= FTE_SPECULAR_MULTIPLIER;
|
||||
//NOTE: rtlights tend to have a *4 scaler here to over-emphasise the effect because it looks cool.
|
||||
//As not all maps will have deluxemapping, and the double-cos from the light util makes everything far too dark anyway,
|
||||
//we default to something that is not garish when the light value is directly infront of every single pixel.
|
||||
//we can justify this difference due to the rtlight editor etc showing the *4.
|
||||
gl_FragColor.rgb += spec * specs.rgb;
|
||||
#endif
|
||||
// col *= factor_base;
|
||||
#define dielectricSpecular 0.04
|
||||
#ifdef SPECULAR
|
||||
vec4 specs = texture2D(s_specular, tc);//*factor_spec;
|
||||
#ifdef ORM
|
||||
#define occlusion specs.r
|
||||
#define roughness specs.g
|
||||
#define metalness specs.b
|
||||
#define gloss (1.0-roughness)
|
||||
#define ambientrgb (specrgb+col.rgb)
|
||||
vec3 specrgb = mix(vec3(dielectricSpecular), col.rgb, metalness);
|
||||
col.rgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);
|
||||
#elif defined(SG) //pbr-style specular+glossiness
|
||||
//occlusion needs to be baked in. :(
|
||||
#define roughness (1.0-specs.a)
|
||||
#define gloss specs.a
|
||||
#define specrgb specs.rgb
|
||||
#define ambientrgb (specs.rgb+col.rgb)
|
||||
#else //blinn-phong
|
||||
#define roughness (1.0-specs.a)
|
||||
#define gloss specs.a
|
||||
#define specrgb specs.rgb
|
||||
#define ambientrgb col.rgb
|
||||
#endif
|
||||
#else
|
||||
#define roughness 0.3
|
||||
#define specrgb 1.0 //vec3(dielectricSpecular)
|
||||
#endif
|
||||
|
||||
//add in specular, if applicable.
|
||||
#ifdef PBR
|
||||
col.rgb = DoPBR(norm, normalize(eyevector), deluxe, roughness, col.rgb, specrgb, vec3(0.0,1.0,1.0));//*e_light_mul + e_light_ambient*.25*ambientrgb;
|
||||
#elif defined(gloss)
|
||||
vec3 halfdir = normalize(normalize(eyevector) + deluxe); //this norm should be the deluxemap info instead
|
||||
float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * gloss);
|
||||
spec *= FTE_SPECULAR_MULTIPLIER;
|
||||
//NOTE: rtlights tend to have a *4 scaler here to over-emphasise the effect because it looks cool.
|
||||
//As not all maps will have deluxemapping, and the double-cos from the light util makes everything far too dark anyway,
|
||||
//we default to something that is not garish when the light value is directly infront of every single pixel.
|
||||
//we can justify this difference due to the rtlight editor etc showing the *4.
|
||||
col.rgb += spec * specrgb;
|
||||
#endif
|
||||
|
||||
#ifdef REFLECTCUBEMASK
|
||||
vec3 rtc = reflect(normalize(-eyevector), norm);
|
||||
rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];
|
||||
rtc = (m_model * vec4(rtc.xyz,0.0)).xyz;
|
||||
gl_FragColor.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;
|
||||
col.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;
|
||||
#endif
|
||||
|
||||
#ifdef EIGHTBIT //FIXME: with this extra flag, half the permutations are redundant.
|
||||
lightmaps *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1.
|
||||
float pal = texture2D(s_paletted, tc).r; //the palette index. hopefully not interpolated.
|
||||
lightmaps -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest
|
||||
gl_FragColor.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.
|
||||
gl_FragColor.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.
|
||||
gl_FragColor.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.
|
||||
col.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.
|
||||
col.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.
|
||||
col.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.
|
||||
#else
|
||||
//now we have our diffuse+specular terms, modulate by lightmap values.
|
||||
gl_FragColor.rgb *= lightmaps.rgb;
|
||||
col.rgb *= lightmaps.rgb;
|
||||
|
||||
//add on the fullbright
|
||||
#ifdef FULLBRIGHT
|
||||
gl_FragColor.rgb += texture2D(s_fullbright, tc).rgb;
|
||||
col.rgb += texture2D(s_fullbright, tc).rgb;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//entity modifiers
|
||||
gl_FragColor = gl_FragColor * e_colourident;
|
||||
col *= e_colourident;
|
||||
|
||||
#if defined(MASK)
|
||||
#if defined(MASKLT)
|
||||
if (gl_FragColor.a < MASK)
|
||||
if (col.a < MASK)
|
||||
discard;
|
||||
#else
|
||||
if (gl_FragColor.a >= MASK)
|
||||
if (col.a >= MASK)
|
||||
discard;
|
||||
#endif
|
||||
gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog.
|
||||
col.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog.
|
||||
#endif
|
||||
|
||||
//and finally hide it all if we're fogged.
|
||||
#ifdef FOG
|
||||
gl_FragColor = fog4(gl_FragColor);
|
||||
#endif
|
||||
gl_FragColor = fog4(col);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
!!samps =PCF shadowmap
|
||||
!!samps =CUBE projectionmap
|
||||
|
||||
#if defined(ORM) || defined(SG)
|
||||
#define PBR
|
||||
#endif
|
||||
|
||||
#include "sys/defs.h"
|
||||
|
||||
//this is the main shader responsible for realtime dlights.
|
||||
|
@ -69,6 +73,9 @@ void main ()
|
|||
{
|
||||
vec3 n, s, t, w;
|
||||
gl_Position = skeletaltransform_wnst(w,n,s,t);
|
||||
n = normalize(n);
|
||||
s = normalize(s);
|
||||
t = normalize(t);
|
||||
tcbase = v_texcoord; //pass the texture coords straight through
|
||||
#ifdef ORTHO
|
||||
vec3 lightminusvertex = -l_lightdirection;
|
||||
|
@ -97,9 +104,7 @@ void main ()
|
|||
eyevector.z = dot(eyeminusvertex, n.xyz);
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
invsurface[0] = v_svector;
|
||||
invsurface[1] = v_tvector;
|
||||
invsurface[2] = v_normal;
|
||||
invsurface = mat3(v_svector, v_tvector, v_normal);
|
||||
#endif
|
||||
#if defined(PCF) || defined(SPOT) || defined(CUBE) || defined(ORTHO)
|
||||
//for texture projections/shadowmapping on dlights
|
||||
|
@ -229,6 +234,8 @@ void main()
|
|||
#include "sys/offsetmapping.h"
|
||||
#endif
|
||||
|
||||
#include "sys/pbr.h"
|
||||
|
||||
void main ()
|
||||
{
|
||||
#ifdef ORTHO
|
||||
|
@ -277,25 +284,54 @@ void main ()
|
|||
vec4 specs = texture2D(s_specular, tcbase);
|
||||
#endif
|
||||
|
||||
vec3 diff;
|
||||
#ifdef NOBUMP
|
||||
//surface can only support ambient lighting, even for lights that try to avoid it.
|
||||
diff = bases.rgb * (l_lightcolourscale.x+l_lightcolourscale.y);
|
||||
#else
|
||||
vec3 nl = normalize(lightvector);
|
||||
#ifdef BUMP
|
||||
diff = bases.rgb * (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(bumps, nl), 0.0));
|
||||
#define dielectricSpecular 0.04
|
||||
#ifdef SPECULAR
|
||||
#ifdef ORM //pbr-style occlusion+roughness+metalness
|
||||
#define occlusion specs.r
|
||||
#define roughness clamp(specs.g, 0.04, 1.0)
|
||||
#define metalness specs.b
|
||||
#define gloss 1.0 //sqrt(1.0-roughness)
|
||||
#define ambientrgb (specrgb+col.rgb)
|
||||
vec3 specrgb = mix(vec3(dielectricSpecular), bases.rgb, metalness);
|
||||
bases.rgb = bases.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);
|
||||
#elif defined(SG) //pbr-style specular+glossiness
|
||||
//occlusion needs to be baked in. :(
|
||||
#define roughness (1.0-specs.a)
|
||||
#define gloss specs.a
|
||||
#define specrgb specs.rgb
|
||||
#define ambientrgb (specs.rgb+col.rgb)
|
||||
#else //blinn-phong
|
||||
#define roughness (1.0-specs.a)
|
||||
#define gloss specs.a
|
||||
#define specrgb specs.rgb
|
||||
#define ambientrgb col.rgb
|
||||
#endif
|
||||
#else
|
||||
//we still do bumpmapping even without bumps to ensure colours are always sane. light.exe does it too.
|
||||
diff = bases.rgb * (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(vec3(0.0, 0.0, 1.0), nl), 0.0));
|
||||
#define roughness 0.3
|
||||
#define specrgb 1.0 //vec3(dielectricSpecular)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SPECULAR
|
||||
vec3 halfdir = normalize(normalize(eyevector) + nl);
|
||||
float spec = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * specs.a)*float(SPECMUL);
|
||||
diff += l_lightcolourscale.z * spec * specs.rgb;
|
||||
#ifdef PBR
|
||||
vec3 diff = DoPBR(bumps, normalize(eyevector), normalize(lightvector), roughness, bases.rgb, specrgb, l_lightcolourscale);
|
||||
#else
|
||||
vec3 diff;
|
||||
#ifdef NOBUMP
|
||||
//surface can only support ambient lighting, even for lights that try to avoid it.
|
||||
diff = bases.rgb * (l_lightcolourscale.x+l_lightcolourscale.y);
|
||||
#else
|
||||
vec3 nl = normalize(lightvector);
|
||||
#ifdef BUMP
|
||||
diff = bases.rgb * (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(bumps, nl), 0.0));
|
||||
#else
|
||||
//we still do bumpmapping even without bumps to ensure colours are always sane. light.exe does it too.
|
||||
diff = bases.rgb * (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(vec3(0.0, 0.0, 1.0), nl), 0.0));
|
||||
#endif
|
||||
#endif
|
||||
#ifdef SPECULAR
|
||||
vec3 halfdir = normalize(normalize(eyevector) + nl);
|
||||
float spec = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * gloss)*float(SPECMUL);
|
||||
diff += l_lightcolourscale.z * spec * specrgb;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef REFLECTCUBEMASK
|
||||
|
@ -314,11 +350,15 @@ void main ()
|
|||
/*2d projection, not used*/
|
||||
// diff *= texture2d(s_projectionmap, shadowcoord);
|
||||
#endif
|
||||
#if defined(occlusion) && !defined(NOOCCLUDE)
|
||||
diff *= occlusion;
|
||||
#endif
|
||||
#if defined(VERTEXCOLOURS)
|
||||
diff *= vc.rgb * vc.a;
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(fog3additive(diff*colorscale*l_lightcolour), 1.0);
|
||||
diff *= colorscale*l_lightcolour;
|
||||
gl_FragColor = vec4(fog3additive(diff), 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -4668,7 +4668,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
|
|||
}
|
||||
#endif
|
||||
}
|
||||
if (info->srgb != 1 && (vid.flags & VID_SRGB_FB))
|
||||
if (info->srgb > 0 && (vid.flags & VID_SRGB_FB))
|
||||
vid.flags |= VID_SRGBAWARE;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,12 @@ extern modplugfuncs_t *modfuncs;
|
|||
|
||||
#define GLTFMODELS
|
||||
|
||||
|
||||
//'The units for all linear distances are meters.'
|
||||
//'feh: 1 metre is approx. 26.24671916 qu.'
|
||||
//if the player is 1.6m tall, and the player's model is around 48qu, then 1m=30qu, which is a slightly nicer number to work with, and 1qu is a really poorly defined unit.
|
||||
#define GLTFSCALE 30
|
||||
|
||||
#ifdef GLTFMODELS
|
||||
typedef struct json_s
|
||||
{
|
||||
|
@ -283,6 +289,10 @@ static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback)
|
|||
l = MAX_QPATH-1;
|
||||
memcpy(tmp, t->bodystart, l);
|
||||
tmp[l] = 0;
|
||||
if (!strcmp(tmp, "false")) //special cases, for booleans
|
||||
return 0;
|
||||
if (!strcmp(tmp, "true")) //special cases, for booleans
|
||||
return 1;
|
||||
return (qintptr_t)strtoll(tmp, NULL, 0);
|
||||
}
|
||||
return fallback;
|
||||
|
@ -490,11 +500,12 @@ typedef struct gltf_s
|
|||
unsigned int numsurfaces;
|
||||
json_t *r;
|
||||
|
||||
int bonemap[MAX_BONES]; //remap skinned bones. I hate that we have to do this.
|
||||
int *bonemap;//[MAX_BONES]; //remap skinned bones. I hate that we have to do this.
|
||||
struct gltfbone_s
|
||||
{
|
||||
char name[32];
|
||||
int parent;
|
||||
int camera;
|
||||
double amatrix[16];
|
||||
double inverse[16];
|
||||
struct
|
||||
|
@ -507,7 +518,7 @@ typedef struct gltf_s
|
|||
struct gltf_accessor *input;
|
||||
struct gltf_accessor *output;
|
||||
} *rot, *scale, *translation;
|
||||
} bones[MAX_BONES];
|
||||
} *bones;//[MAX_BONES];
|
||||
unsigned int numbones;
|
||||
|
||||
int warnlimit; //don't spam warnings. this is a loader, not a spammer
|
||||
|
@ -924,7 +935,7 @@ static void *GLTF_AccessorToDataUB(gltf_t *gltf, size_t outverts, unsigned int o
|
|||
static void *GLTF_AccessorToDataBone(gltf_t *gltf, size_t outverts, struct gltf_accessor *a)
|
||||
{ //input should only be ubytes||ushorts.
|
||||
const unsigned int outcomponents = 4;
|
||||
unsigned char *ret = modfuncs->ZG_Malloc(&gltf->mod->memgroup, sizeof(*ret) * outcomponents * outverts), *o;
|
||||
boneidx_t *ret = modfuncs->ZG_Malloc(&gltf->mod->memgroup, sizeof(*ret) * outcomponents * outverts), *o;
|
||||
char *in = a->data;
|
||||
|
||||
|
||||
|
@ -964,7 +975,7 @@ static void *GLTF_AccessorToDataBone(gltf_t *gltf, size_t outverts, struct gltf_
|
|||
for (c = 0; c < ic; c++)
|
||||
{
|
||||
v = ((unsigned short*)in)[c];
|
||||
if (v > 255)
|
||||
if (v > MAX_BONES)
|
||||
v = 0;
|
||||
o[c] = gltf->bonemap[v];
|
||||
}
|
||||
|
@ -974,6 +985,7 @@ static void *GLTF_AccessorToDataBone(gltf_t *gltf, size_t outverts, struct gltf_
|
|||
in += a->bytestride;
|
||||
}
|
||||
break;
|
||||
//the spec doesn't require these.
|
||||
// case 5125: //UNSIGNED_INT
|
||||
/* case 5126: //FLOAT
|
||||
while(outverts --> 0)
|
||||
|
@ -1117,8 +1129,9 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
{
|
||||
qboolean doubleSided;
|
||||
int alphaMode;
|
||||
//double alphaCutoff;
|
||||
double alphaCutoff;
|
||||
char shader[8192];
|
||||
char alphaCutoffmodifier[128];
|
||||
json_t *mat = JSON_FindIndexedChild(gltf->r, "materials", material);
|
||||
galiasskin_t *ret;
|
||||
|
||||
|
@ -1130,19 +1143,8 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
pbrmr = JSON_FindChild(mat, "pbrMetallicRoughness");
|
||||
blinn = JSON_FindChild(mat, "extensions.KHR_materials_cmnBlinnPhong");
|
||||
|
||||
/* JSON_WarnIfChild(mat, "name");
|
||||
JSON_WarnIfChild(pbrsg, "diffuseFactor");
|
||||
JSON_WarnIfChild(pbrsg, "diffuseTexture");
|
||||
JSON_WarnIfChild(pbrsg, "specularFactor");
|
||||
JSON_WarnIfChild(pbrsg, "glossinessFactor");
|
||||
JSON_WarnIfChild(pbrsg, "specularGlossinessTexture");
|
||||
JSON_WarnIfChild(mat, "normalTexture");
|
||||
JSON_WarnIfChild(mat, "occlusionTexture");
|
||||
JSON_WarnIfChild(mat, "emissiveTexture");
|
||||
JSON_WarnIfChild(mat, "emissiveFactor"); //0,0,0
|
||||
*/
|
||||
doubleSided = JSON_GetInteger(mat, "doubleSided", false);
|
||||
//alphaCutoff = JSON_GetInteger(mat, "alphaCutoff", 0.5);
|
||||
alphaCutoff = JSON_GetFloat(mat, "alphaCutoff", 0.5);
|
||||
if (JSON_Equals(mat, "alphaMode", "MASK"))
|
||||
alphaMode = 1;
|
||||
else if (JSON_Equals(mat, "alphaMode", "BLEND"))
|
||||
|
@ -1162,6 +1164,11 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
else
|
||||
Q_snprintf(ret->frame->shadername, sizeof(ret->frame->shadername), "%i", material);
|
||||
|
||||
if (alphaMode == 1)
|
||||
Q_snprintf(alphaCutoffmodifier, sizeof(alphaCutoffmodifier), "#ALPHATEST=>%f", alphaCutoff);
|
||||
else
|
||||
*alphaCutoffmodifier = 0;
|
||||
|
||||
if (unlit)
|
||||
{ //if this extension was present, then we don't get ANY lighting info.
|
||||
int albedo = JSON_GetInteger(pbrmr, "baseColorTexture.index", -1); //.rgba
|
||||
|
@ -1171,7 +1178,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
"{\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"%s"//cull
|
||||
"program default2d\n" //fixme: there's no gpu skeletal stuff with this prog
|
||||
"program default2d%s\n" //fixme: there's no gpu skeletal stuff with this prog
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"%s" //blend
|
||||
|
@ -1179,8 +1186,9 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
"}\n"
|
||||
"fte_basefactor %f %f %f %f\n"
|
||||
"}\n",
|
||||
doubleSided?"cullface disable\n":"",
|
||||
(alphaMode==1)?"alphamask\n":(alphaMode==2)?"blendfunc blend\n":"",
|
||||
doubleSided?"cull disable\n":"",
|
||||
alphaCutoffmodifier,
|
||||
(alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"",
|
||||
vertexcolours?"rgbgen vertex\nalphagen vertex\n":"",
|
||||
JSON_GetFloat(pbrmr, "baseColorFactor.0", 1),
|
||||
JSON_GetFloat(pbrmr, "baseColorFactor.1", 1),
|
||||
|
@ -1204,7 +1212,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
Q_snprintf(shader, sizeof(shader),
|
||||
"{\n"
|
||||
"%s"//cull
|
||||
"program defaultskin#VC\n"
|
||||
"program defaultskin#VC%s\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"%s" //blend
|
||||
|
@ -1214,20 +1222,21 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
"fte_specularfactor %f %f %f %f\n"
|
||||
"fte_fullbrightfactor %f %f %f 1.0\n"
|
||||
"}\n",
|
||||
doubleSided?"cullface disable\n":"",
|
||||
(alphaMode==1)?"alphamask\n":(alphaMode==2)?"blendfunc blend\n":"",
|
||||
doubleSided?"cull disable\n":"",
|
||||
alphaCutoffmodifier,
|
||||
(alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"",
|
||||
vertexcolours?"rgbgen vertex\nalphagen vertex\n":"",
|
||||
JSON_GetFloat(pbrsg, "diffuseFactor.0", 1),
|
||||
JSON_GetFloat(pbrsg, "diffuseFactor.1", 1),
|
||||
JSON_GetFloat(pbrsg, "diffuseFactor.2", 1),
|
||||
JSON_GetFloat(pbrsg, "diffuseFactor.3", 1),
|
||||
JSON_GetFloat(pbrsg, "specularFactor.0", 1),
|
||||
JSON_GetFloat(pbrsg, "specularFactor.0", 1), //FIXME: divide by gl_specular
|
||||
JSON_GetFloat(pbrsg, "specularFactor.1", 1),
|
||||
JSON_GetFloat(pbrsg, "specularFactor.2", 1),
|
||||
JSON_GetFloat(pbrsg, "shininessFactor", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.0", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.1", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.2", 1)
|
||||
JSON_GetFloat(pbrsg, "shininessFactor", 1), //FIXME: divide by gl_specular_power
|
||||
JSON_GetFloat(mat, "emissiveFactor.0", 0),
|
||||
JSON_GetFloat(mat, "emissiveFactor.1", 0),
|
||||
JSON_GetFloat(mat, "emissiveFactor.2", 0)
|
||||
);
|
||||
}
|
||||
else if (pbrsg)
|
||||
|
@ -1238,7 +1247,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
Q_snprintf(shader, sizeof(shader),
|
||||
"{\n"
|
||||
"%s"//cull
|
||||
"program defaultskin#VC\n"
|
||||
"program defaultskin#SG#VC#NOOCCLUDE%s\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"%s" //blend
|
||||
|
@ -1247,9 +1256,11 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
"fte_basefactor %f %f %f %f\n"
|
||||
"fte_specularfactor %f %f %f %f\n"
|
||||
"fte_fullbrightfactor %f %f %f 1.0\n"
|
||||
"bemode rtlight rtlight_sg\n"
|
||||
"}\n",
|
||||
doubleSided?"cullface disable\n":"",
|
||||
(alphaMode==1)?"alphamask\n":(alphaMode==2)?"blendfunc blend\n":"",
|
||||
doubleSided?"cull disable\n":"",
|
||||
alphaCutoffmodifier,
|
||||
(alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"",
|
||||
vertexcolours?"rgbgen vertex\nalphagen vertex\n":"",
|
||||
JSON_GetFloat(pbrsg, "diffuseFactor.0", 1),
|
||||
JSON_GetFloat(pbrsg, "diffuseFactor.1", 1),
|
||||
|
@ -1259,9 +1270,9 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
JSON_GetFloat(pbrsg, "specularFactor.1", 1),
|
||||
JSON_GetFloat(pbrsg, "specularFactor.2", 1),
|
||||
JSON_GetFloat(pbrsg, "glossinessFactor", 1)*32, //this is fucked.
|
||||
JSON_GetFloat(mat, "emissiveFactor.0", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.1", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.2", 1)
|
||||
JSON_GetFloat(mat, "emissiveFactor.0", 0),
|
||||
JSON_GetFloat(mat, "emissiveFactor.1", 0),
|
||||
JSON_GetFloat(mat, "emissiveFactor.2", 0)
|
||||
);
|
||||
}
|
||||
else if (pbrmr)
|
||||
|
@ -1270,45 +1281,52 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
|
|||
int mrt = JSON_GetInteger(pbrmr, "metallicRoughnessTexture.index", -1); //.r = unused, .g = roughness, .b = metalic, .a = unused
|
||||
int occ = JSON_GetInteger(mat, "occlusionTexture.index", -1); //.r
|
||||
|
||||
//now work around potential lame exporters.
|
||||
//now work around potential lame exporters (yay dds?).
|
||||
occ = JSON_GetInteger(mat, "extensions.MSFT_packing_occlusionRoughnessMetallic.occlusionRoughnessMetallicTexture.index", occ);
|
||||
mrt = JSON_GetInteger(mat, "extensions.MSFT_packing_occlusionRoughnessMetallic.occlusionRoughnessMetallicTexture.index", mrt);
|
||||
|
||||
if (occ != mrt && occ != -1) //if its -1 then the mrt should have an unused channel set to 1. however, this isn't guarenteed...
|
||||
{
|
||||
occ = -1; //not supported. fixme: support some weird loadtexture channel merging stuff
|
||||
if (gltf->warnlimit --> 0)
|
||||
Con_Printf(CON_WARNING"%s: Separate occlusion and metallicRoughness textures are not supported\n", gltf->mod->name);
|
||||
}
|
||||
|
||||
//note: extensions.MSFT_packing_normalRoughnessMetallic.normalRoughnessMetallicTexture.index gives rg=normalxy, b=roughness, .a=metalic
|
||||
//(would still need an ao map, and probably wouldn't work well as bc3 either)
|
||||
|
||||
ret->frame->texnums.base = GLTF_LoadTexture(gltf, albedo, 0);
|
||||
ret->frame->texnums.specular = GLTF_LoadTexture(gltf, mrt, 0);
|
||||
ret->frame->texnums.specular = GLTF_LoadTexture(gltf, mrt, IF_NOSRGB);
|
||||
|
||||
Q_snprintf(shader, sizeof(shader),
|
||||
"{\n"
|
||||
"%s"//cull
|
||||
"program defaultskin#PBR_ORM#VC\n"
|
||||
"program defaultskin#ORM#VC%s%s\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"%s" //blend
|
||||
"%s" //rgbgen
|
||||
"}\n"
|
||||
"fte_basefactor %f %f %f %f\n"
|
||||
"fte_specularfactor 1.0 %f %f 1.0\n"
|
||||
"fte_specularfactor %f %f %f 1.0\n"
|
||||
"fte_fullbrightfactor %f %f %f 1.0\n"
|
||||
"bemode rtlight rtlight_orm\n"
|
||||
"}\n",
|
||||
doubleSided?"cullface disable\n":"",
|
||||
(alphaMode==1)?"alphamask\n":(alphaMode==2)?"blendfunc blend\n":"",
|
||||
doubleSided?"cull disable\n":"",
|
||||
(occ==-1)?"#NOOCCLUDE":"",
|
||||
alphaCutoffmodifier,
|
||||
(alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"",
|
||||
vertexcolours?"rgbgen vertex\nalphagen vertex\n":"",
|
||||
JSON_GetFloat(pbrmr, "baseColorFactor.0", 1),
|
||||
JSON_GetFloat(pbrmr, "baseColorFactor.1", 1),
|
||||
JSON_GetFloat(pbrmr, "baseColorFactor.2", 1),
|
||||
JSON_GetFloat(pbrmr, "baseColorFactor.3", 1),
|
||||
JSON_GetFloat(pbrmr, "metallicFactor", 1),
|
||||
JSON_GetFloat(pbrmr, "roughnessFactor", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.0", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.1", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.2", 1)
|
||||
JSON_GetFloat(mat, "occlusionTexture.strength", 1),
|
||||
JSON_GetFloat(pbrmr, "metallicFactor", 1),
|
||||
JSON_GetFloat(pbrmr, "roughnessFactor", 1),
|
||||
JSON_GetFloat(mat, "emissiveFactor.0", 0),
|
||||
JSON_GetFloat(mat, "emissiveFactor.1", 0),
|
||||
JSON_GetFloat(mat, "emissiveFactor.2", 0)
|
||||
);
|
||||
}
|
||||
ret->frame->texnums.bump = GLTF_LoadTexture(gltf, JSON_GetInteger(mat, "normalTexture.index", -1), IF_NOSRGB|IF_TRYBUMP);
|
||||
|
@ -1374,9 +1392,14 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, int meshidx, int basebone, double
|
|||
|
||||
surf = modfuncs->ZG_Malloc(&mod->memgroup, sizeof(*surf));
|
||||
|
||||
surf->surfaceid = meshidx;
|
||||
surf->contents = FTECONTENTS_BODY;
|
||||
surf->csurface.flags = 0;
|
||||
surf->surfaceid = surf->contents = JSON_GetInteger(prim, "extras.fte.surfaceid", meshidx);
|
||||
surf->contents = JSON_GetInteger(prim, "extras.fte.contents", FTECONTENTS_BODY);
|
||||
surf->csurface.flags = JSON_GetInteger(prim, "extras.fte.surfaceflags", 0);
|
||||
surf->geomset = JSON_GetInteger(prim, "extras.fte.geomset", ~0u);
|
||||
surf->geomid = JSON_GetInteger(prim, "extras.fte.geomid", 0);
|
||||
surf->mindist = JSON_GetInteger(prim, "extras.fte.mindist", 0);
|
||||
surf->maxdist = JSON_GetInteger(prim, "extras.fte.maxdist", 0);
|
||||
|
||||
surf->shares_bones = gltf->numsurfaces;
|
||||
surf->shares_verts = gltf->numsurfaces;
|
||||
JSON_ReadBody(meshname, surf->surfacename, sizeof(surf->surfacename));
|
||||
|
@ -1474,6 +1497,12 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, int meshidx, int basebone, double
|
|||
surf->numskins = 1;
|
||||
surf->ofsskins = GLTF_LoadMaterial(gltf, mat, surf->ofs_rgbaub||surf->ofs_rgbaf);
|
||||
|
||||
if (!tang.data)
|
||||
{
|
||||
modfuncs->AccumulateTextureVectors(surf->ofs_skel_xyz, surf->ofs_st_array, surf->ofs_skel_norm, surf->ofs_skel_svect, surf->ofs_skel_tvect, surf->ofs_indexes, surf->numindexes, !norm.data);
|
||||
modfuncs->NormaliseTextureVectors(surf->ofs_skel_norm, surf->ofs_skel_svect, surf->ofs_skel_tvect, surf->numverts, !norm.data);
|
||||
}
|
||||
|
||||
gltf->numsurfaces++;
|
||||
surf->nextsurf = mod->meshinfo;
|
||||
mod->meshinfo = surf;
|
||||
|
@ -1551,10 +1580,16 @@ static qboolean GLTF_ProcessNode(gltf_t *gltf, int nodeidx, double pmatrix[16],
|
|||
int skinidx;
|
||||
struct gltfbone_s *b;
|
||||
if (nodeidx < 0 || nodeidx >= gltf->numbones)
|
||||
{
|
||||
Con_Printf(CON_WARNING"%s: Invalid node index %i\n", gltf->mod->name, nodeidx);
|
||||
return false;
|
||||
}
|
||||
node = JSON_FindIndexedChild(gltf->r, "nodes", nodeidx);
|
||||
if (!node)
|
||||
{
|
||||
Con_Printf(CON_WARNING"%s: Invalid node index %i\n", gltf->mod->name, nodeidx);
|
||||
return false;
|
||||
}
|
||||
|
||||
b = &gltf->bones[nodeidx];
|
||||
b->parent = parentidx;
|
||||
|
@ -1638,7 +1673,7 @@ static qboolean GLTF_ProcessNode(gltf_t *gltf, int nodeidx, double pmatrix[16],
|
|||
inversef = inverse.data;
|
||||
if (inverse.componentType != 5126/*FLOAT*/ || inverse.type != ((4<<8) | 4)/*mat4x4*/)
|
||||
inverse.count = 0;
|
||||
for (j = 0; j < countof(gltf->bonemap); j++, inversef+=inverse.bytestride/sizeof(float))
|
||||
for (j = 0; j < MAX_BONES; j++, inversef+=inverse.bytestride/sizeof(float))
|
||||
{
|
||||
int b = JSON_GetIndexedInteger(joints, j, -1);
|
||||
if (b < 0)
|
||||
|
@ -1705,7 +1740,7 @@ static qboolean GLTF_ProcessNode(gltf_t *gltf, int nodeidx, double pmatrix[16],
|
|||
GLTF_ProcessNode(gltf, JSON_GetInteger(c, NULL, -1), b->amatrix, nodeidx, isjoint);
|
||||
}
|
||||
|
||||
JSON_FlagAsUsed(node, "camera");
|
||||
b->camera = JSON_GetInteger(node, "camera", -1);
|
||||
|
||||
JSON_WarnIfChild(node, "weights", &gltf->warnlimit); //default value for morph weight animations
|
||||
JSON_WarnIfChild(node, "extensions", &gltf->warnlimit);
|
||||
|
@ -1798,8 +1833,8 @@ static void LerpAnimData(gltf_t *gltf, struct gltf_animsampler *samp, float time
|
|||
struct gltf_accessor *in = &samp->input;
|
||||
struct gltf_accessor *out = &samp->output;
|
||||
|
||||
t1 = t2 = Anim_GetTime(in, 0);
|
||||
for (f2 = 1 ; f2 < in->count; f2++)
|
||||
t1 = t2 = Anim_GetTime(in, f1);
|
||||
for (f2 = 1; f2 < in->count; f2++)
|
||||
{
|
||||
t2 = Anim_GetTime(in, f2);
|
||||
if (t2 > time)
|
||||
|
@ -1808,19 +1843,35 @@ static void LerpAnimData(gltf_t *gltf, struct gltf_animsampler *samp, float time
|
|||
f1 = f2;
|
||||
}
|
||||
|
||||
//assume linear
|
||||
if (f1==f2 || t1==t2)
|
||||
{
|
||||
Anim_GetVal(out, f1, result, elems);
|
||||
return;
|
||||
if (time <= t1)
|
||||
{ //if before the first time, clamp it.
|
||||
w1 = 1;
|
||||
w2 = 0;
|
||||
}
|
||||
else if (time >= t2)
|
||||
{ //if after tha last frame we could find, clamp it to the last.
|
||||
w1 = 0;
|
||||
w2 = 1;
|
||||
}
|
||||
else
|
||||
{ //assume linear
|
||||
w2 = (time-t1)/(t2-t1);
|
||||
// if (1) //step it. it'll still get lerped though. :(
|
||||
// w2 = (w2>0.5)?1:0;
|
||||
w1 = 1-w2;
|
||||
}
|
||||
w2 = (time-t1)/(t2-t1);
|
||||
w1 = 1-w2;
|
||||
|
||||
Anim_GetVal(out, f1, v1, elems);
|
||||
Anim_GetVal(out, f2, v2, elems);
|
||||
for (c = 0; c < elems; c++)
|
||||
result[c] = v1[c]*w1 + w2*v2[c];
|
||||
if (w1 >= 1)
|
||||
Anim_GetVal(out, f1, result, elems);
|
||||
else if (w2 >= 1)
|
||||
Anim_GetVal(out, f2, result, elems);
|
||||
else
|
||||
{
|
||||
Anim_GetVal(out, f1, v1, elems);
|
||||
Anim_GetVal(out, f2, v2, elems);
|
||||
for (c = 0; c < elems; c++)
|
||||
result[c] = v1[c]*w1 + w2*v2[c];
|
||||
}
|
||||
}
|
||||
|
||||
static void GLTF_RemapBone(gltf_t *gltf, int *nextidx, int b)
|
||||
|
@ -1877,6 +1928,20 @@ static void GLTF_RewriteBoneTree(gltf_t *gltf)
|
|||
//we do NOT supported nested nodes right now...
|
||||
static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize, void *buffer, size_t buffersize)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
qboolean supported; //unsupported extensions don't really need to be listed, but they do prevent warnings from unkown-but-used extensions
|
||||
} extensions[] =
|
||||
{
|
||||
{"KHR_materials_pbrSpecularGlossiness", true},
|
||||
//draft {"KHR_materials_cmnBlinnPhong", true},
|
||||
{"KHR_materials_unlit", true},
|
||||
{"KHR_texture_transform", false},
|
||||
{"KHR_draco_mesh_compression", false},
|
||||
{"MSFT_texture_dds", true},
|
||||
{"MSFT_packing_occlusionRoughnessMetallic", true},
|
||||
};
|
||||
gltf_t gltf;
|
||||
int pos=0, j, k;
|
||||
json_t *scene, *n, *anim;
|
||||
|
@ -1888,6 +1953,9 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
unsigned int numframegroups = 0;
|
||||
float *baseframe;
|
||||
memset(&gltf, 0, sizeof(gltf));
|
||||
gltf.bonemap = malloc(sizeof(*gltf.bonemap)*MAX_BONES);
|
||||
gltf.bones = malloc(sizeof(*gltf.bones)*MAX_BONES);
|
||||
memset(gltf.bones, 0, sizeof(*gltf.bones)*MAX_BONES);
|
||||
gltf.r = JSON_Parse(NULL, mod->name, NULL, json, &pos, jsonsize);
|
||||
gltf.mod = mod;
|
||||
gltf.buffers[0].data = buffer;
|
||||
|
@ -1909,23 +1977,33 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
{
|
||||
char extname[256];
|
||||
JSON_ReadBody(n, extname, sizeof(extname));
|
||||
Con_Printf(CON_ERROR "%s: Required gltf2 extension \"%s\" not supported\n", mod->name, extname);
|
||||
for (j = 0; j < countof(extensions); j++)
|
||||
{
|
||||
if (!strcmp(extname, extensions[j].name))
|
||||
break;
|
||||
}
|
||||
if (j==countof(extensions) || !extensions[j].supported)
|
||||
Con_Printf(CON_ERROR "%s: Required gltf2 extension \"%s\" not supported\n", mod->name, extname);
|
||||
|
||||
JSON_Destroy(gltf.r);
|
||||
return false;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
for(n = JSON_FindIndexedChild(gltf.r, "extensionsUsed", 0); n; n = n->sibling)
|
||||
{ //must be a superset of the above.
|
||||
char extname[256];
|
||||
JSON_ReadBody(n, extname, sizeof(extname));
|
||||
if (!strcmp(extname, "KHR_materials_pbrSpecularGlossiness"))
|
||||
;
|
||||
else if (!strcmp(extname, "KHR_texture_transform"))
|
||||
;
|
||||
else
|
||||
for (j = 0; j < countof(extensions); j++)
|
||||
{
|
||||
if (!strcmp(extname, extensions[j].name))
|
||||
break;
|
||||
}
|
||||
if (j==countof(extensions) || !extensions[j].supported)
|
||||
Con_Printf(CON_WARNING "%s: gltf2 extension \"%s\" not known\n", mod->name, extname);
|
||||
}
|
||||
|
||||
VectorClear(mod->maxs);
|
||||
VectorClear(mod->mins);
|
||||
|
||||
//we don't really care about cameras.
|
||||
JSON_FlagAsUsed(gltf.r, "cameras");
|
||||
|
||||
|
@ -1933,16 +2011,21 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
|
||||
memset(&rootmatrix, 0, sizeof(rootmatrix));
|
||||
#if 1 //transform from gltf to quake. mostly only needed for the base pose.
|
||||
rootmatrix[2] = rootmatrix[4] = rootmatrix[9] = 1; rootmatrix[15] = 1;
|
||||
rootmatrix[2] = rootmatrix[4] = rootmatrix[9] = GLTFSCALE; rootmatrix[15] = 1;
|
||||
#else
|
||||
rootmatrix[0] = rootmatrix[5] = rootmatrix[10] = 1; rootmatrix[15] = 1;
|
||||
#endif
|
||||
|
||||
for (j = 0; j < countof(gltf.bones); j++)
|
||||
for (j = 0; ; j++)
|
||||
{
|
||||
n = JSON_FindIndexedChild(gltf.r, "nodes", j);
|
||||
if (!n)
|
||||
break;
|
||||
if (j == MAX_BONES)
|
||||
{
|
||||
Con_Printf(CON_WARNING"%s: too many nodes (max %i)\n", mod->name, MAX_BONES);
|
||||
break;
|
||||
}
|
||||
if (!JSON_ReadBody(JSON_FindChild(n, "name"), gltf.bones[j].name, sizeof(gltf.bones[j].name)))
|
||||
{
|
||||
if (n)
|
||||
|
@ -1950,6 +2033,7 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
else
|
||||
Q_snprintf(gltf.bones[j].name, sizeof(gltf.bones[j].name), "bone%i", j);
|
||||
}
|
||||
gltf.bones[j].camera = -1;
|
||||
gltf.bones[j].parent = -1;
|
||||
gltf.bones[j].amatrix[0] = gltf.bones[j].amatrix[5] = gltf.bones[j].amatrix[10] = gltf.bones[j].amatrix[15] = 1;
|
||||
gltf.bones[j].inverse[0] = gltf.bones[j].inverse[5] = gltf.bones[j].inverse[10] = gltf.bones[j].inverse[15] = 1;
|
||||
|
@ -1966,8 +2050,9 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
if (!n)
|
||||
break;
|
||||
n->used = true;
|
||||
if (!GLTF_ProcessNode(&gltf, JSON_GetInteger(n, NULL, -1), rootmatrix, -1, false))
|
||||
break;
|
||||
// if (!
|
||||
GLTF_ProcessNode(&gltf, JSON_GetInteger(n, NULL, -1), rootmatrix, -1, false);
|
||||
// break;
|
||||
}
|
||||
|
||||
GLTF_RewriteBoneTree(&gltf);
|
||||
|
@ -1979,6 +2064,9 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
Q_strlcpy(bone[j].name, gltf.bones[j].name, sizeof(bone[j].name));
|
||||
bone[j].parent = gltf.bones[j].parent;
|
||||
|
||||
if (gltf.bones[j].camera >= 0 && !mod->camerabone)
|
||||
mod->camerabone = j+1;
|
||||
|
||||
for(k = 0; k < 12; k++)
|
||||
{
|
||||
baseframe[j*12+k] = gltf.bones[j].amatrix[k];
|
||||
|
@ -1990,6 +2078,10 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
numframegroups++;
|
||||
if (numframegroups)
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct gltf_animsampler rot,scale,trans;
|
||||
} *b = malloc(sizeof(*b)*gltf.numbones);
|
||||
framegroups = modfuncs->ZG_Malloc(&mod->memgroup, sizeof(*framegroups)*numframegroups);
|
||||
for (k = 0; k < numframegroups; k++)
|
||||
{
|
||||
|
@ -1999,11 +2091,7 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
json_t *samps = JSON_FindChild(anim, "samplers");
|
||||
int f, l;
|
||||
float maxtime = 0;
|
||||
struct
|
||||
{
|
||||
struct gltf_animsampler rot,scale,trans;
|
||||
} b[MAX_BONES];
|
||||
memset(b, 0, sizeof(b));
|
||||
memset(b, 0, sizeof(*b)*gltf.numbones);
|
||||
|
||||
if (!JSON_ReadBody(JSON_FindChild(anim, "name"), fg->name, sizeof(fg->name)))
|
||||
{
|
||||
|
@ -2041,14 +2129,14 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
else if (gltf.warnlimit --> 0)
|
||||
{ //these are unsupported
|
||||
if (JSON_Equals(path, NULL, "weights")) //morph weights
|
||||
Con_Printf("%s: morph animations are not supported\n", mod->name);
|
||||
Con_Printf(CON_WARNING"%s: morph animations are not supported\n", mod->name);
|
||||
else
|
||||
Con_Printf("%s: undocumented animation type\n", mod->name);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: make a guess at the framerate according to sampler intervals
|
||||
fg->rate = 30;
|
||||
fg->rate = 60;
|
||||
fg->numposes = max(1, maxtime*fg->rate);
|
||||
if (maxtime)
|
||||
fg->rate = fg->numposes/maxtime; //fix up the rate so we hit the exact end of the animation (so it doesn't have to be quite so exact).
|
||||
|
@ -2089,13 +2177,14 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
if (gltf.bones[j].parent < 0)
|
||||
{ //rotate any root bones from gltf to quake's orientation.
|
||||
float fnar[12];
|
||||
static float toquake[12]={0,0,1,0,1,0,0,0,0,1,0,0};
|
||||
static float toquake[12]={0,0,GLTFSCALE,0,GLTFSCALE,0,0,0,0,GLTFSCALE,0,0};
|
||||
memcpy(fnar, bonematrix, sizeof(fnar));
|
||||
modfuncs->ConcatTransforms((void*)toquake, (void*)fnar, (void*)bonematrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(b);
|
||||
}
|
||||
|
||||
for(surf = mod->meshinfo; surf; surf = surf->nextsurf)
|
||||
|
@ -2111,13 +2200,19 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
|||
surf->geomset = ~0; //invalid set = always visible. FIXME: set this according to scene numbers?
|
||||
surf->geomid = 0;
|
||||
}
|
||||
VectorScale(mod->mins, GLTFSCALE, mod->mins);
|
||||
VectorScale(mod->maxs, GLTFSCALE, mod->maxs);
|
||||
|
||||
if (!mod->meshinfo)
|
||||
Con_Printf("%s: Doesn't contain any meshes...\n", mod->name);
|
||||
JSON_WarnUnused(gltf.r, &gltf.warnlimit);
|
||||
}
|
||||
else
|
||||
Con_Printf("%s: unsupported gltf version (%.2f)\n", mod->name, gltfver);
|
||||
abort:
|
||||
JSON_Destroy(gltf.r);
|
||||
|
||||
free(gltf.bones);
|
||||
free(gltf.bonemap);
|
||||
|
||||
|
||||
mod->type = mod_alias;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
FTE_MULTIPROGS
|
||||
|
||||
void() init; //called before ents are available (spawn() will fail, but you can use addprogs() here)
|
||||
void() initents; //called just before worldspawn, after ents are spawnable spawn() works but addprogs() may fail)
|
||||
void() initents; //called just before worldspawn, after ents are spawnable (spawn() works but addprogs() may fail)
|
||||
|
||||
float thisprogs; //set by the engine. main progs will always be 0, addons will be non-zero and unique.
|
||||
float(string modname) addprogs = #202; //load another progs as well - may fail if too many fields are added.
|
||||
|
@ -54,4 +54,4 @@ initents permits the use of spawn(). spawned ents will be *after* world, even th
|
|||
using addprogs later than the main progs' init function can fail if too many(any) new fields are defined.
|
||||
|
||||
note that a great use of this extension is to add frikbots to any mod without modding it.
|
||||
externvalue and externset do work for the current progs too. it can be used to implement arrays or some kind of scripts (fteqcc's builtin arrays are more efficient).
|
||||
externvalue and externset do work for the current progs too. it can be used to implement arrays or some kind of scripts (fteqcc's builtin arrays are more efficient).
|
||||
|
|
Loading…
Reference in a new issue