mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-25 13:21:36 +00:00
Implement an area grid, primarily to avoid mods(read: xonotic) generating 2000 ents all sitting on the root area node.
Add separate cl_movement cvar to enable/disable reporting input sequences to DP servers (which use different pathways). Does not affect other protocols. This is separate from cl_nopred but will usually have the same result in the long run. Fixed movevalues for DPP7 clients, if they try using prediction they should now (mostly) get the same values that DP normally uses for QW servers. Reworked sky overrides somewhat. Now uses skyboxes where possible. Fixed dpcompat_makeshitup a little, for better compat. Fixed echo $foo$bar not exanding bar. Try to fix the meanings of vid_hardwaregamma. Fixes for builtins/features/etc that apparently only xonotic uses. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5143 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
7c6eb18a76
commit
0f7bbfcf0e
90 changed files with 5704 additions and 2907 deletions
|
@ -1519,9 +1519,12 @@ void CL_Record_f (void)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef Q2SERVER
|
||||
if (cls.protocol == CP_QUAKE2)
|
||||
defaultext = ".dm2";
|
||||
else if (cls.protocol == CP_NETQUAKE && !CPNQ_IS_DP)
|
||||
else
|
||||
#endif
|
||||
if (cls.protocol == CP_NETQUAKE && !CPNQ_IS_DP)
|
||||
defaultext = ".dem";
|
||||
else if (cls.protocol == CP_QUAKEWORLD)
|
||||
defaultext = ".qwd";
|
||||
|
@ -1894,7 +1897,7 @@ void CL_Record_f (void)
|
|||
|
||||
// done
|
||||
break;
|
||||
#ifdef Q2CLIENT
|
||||
#if defined(Q2CLIENT) && defined(Q2SERVER)
|
||||
case CP_QUAKE2:
|
||||
cls.demorecording = DPB_QUAKE2;
|
||||
|
||||
|
|
|
@ -5416,7 +5416,7 @@ void CL_SetSolidEntities (void)
|
|||
pmove.physents[0].info = 0;
|
||||
pmove.numphysent = 1;
|
||||
|
||||
frame = &cl.inframes[parsecountmod];
|
||||
frame = &cl.inframes[cl.validsequence&UPDATE_MASK];
|
||||
pak = &frame->packet_entities;
|
||||
|
||||
for (i=0 ; i<pak->num_entities ; i++)
|
||||
|
|
|
@ -28,6 +28,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
float in_sensitivityscale = 1;
|
||||
|
||||
static void QDECL CL_SpareMsec_Callback (struct cvar_s *var, char *oldvalue);
|
||||
#ifdef NQPROT
|
||||
cvar_t cl_movement = CVARD("cl_movement","1", "Specifies whether to send movement sequence info over DPP7 protocols (other protocols are unaffected). Unlike cl_nopred, this can result in different serverside behaviour.");
|
||||
#endif
|
||||
|
||||
cvar_t cl_nodelta = CVAR("cl_nodelta","0");
|
||||
|
||||
|
@ -48,8 +51,7 @@ cvar_t in_xflip = {"in_xflip", "0"};
|
|||
|
||||
cvar_t prox_inmenu = CVAR("prox_inmenu", "0");
|
||||
|
||||
usercmd_t independantphysics[MAX_SPLITS];
|
||||
vec3_t mousemovements[MAX_SPLITS];
|
||||
usercmd_t cl_pendingcmd[MAX_SPLITS];
|
||||
|
||||
/*kinda a hack...*/
|
||||
unsigned int con_splitmodifier;
|
||||
|
@ -659,36 +661,30 @@ CL_BaseMove
|
|||
Send the intended movement message to the server
|
||||
================
|
||||
*/
|
||||
void CL_BaseMove (usercmd_t *cmd, int pnum, float extra, float wantfps)
|
||||
void CL_BaseMove (usercmd_t *cmd, int pnum, float priortime, float extratime)
|
||||
{
|
||||
float scale = 1;//extra/1000.0f * 1/wantfps;
|
||||
float nscale = extratime?extratime / (extratime+priortime):0;
|
||||
float oscale = 1 - nscale;
|
||||
|
||||
//
|
||||
// adjust for speed key
|
||||
//
|
||||
if ((in_speed.state[pnum] & 1) ^ cl_run.ival)
|
||||
scale *= cl_movespeedkey.value;
|
||||
nscale *= cl_movespeedkey.value;
|
||||
|
||||
if (in_strafe.state[pnum] & 1)
|
||||
{
|
||||
cmd->sidemove += scale*cl_sidespeed.value * CL_KeyState (&in_right, pnum, true);
|
||||
cmd->sidemove -= scale*cl_sidespeed.value * CL_KeyState (&in_left, pnum, true);
|
||||
}
|
||||
cmd->sidemove = cmd->sidemove*oscale + nscale*cl_sidespeed.value * (CL_KeyState (&in_right, pnum, true) - CL_KeyState (&in_left, pnum, true)) * (in_xflip.ival?-1:1);
|
||||
cmd->sidemove = cmd->sidemove*oscale + nscale*cl_sidespeed.value * (CL_KeyState (&in_moveright, pnum, true) - CL_KeyState (&in_moveleft, pnum, true)) * (in_xflip.ival?-1:1);
|
||||
|
||||
cmd->sidemove += scale*cl_sidespeed.value * CL_KeyState (&in_moveright, pnum, true);
|
||||
cmd->sidemove -= scale*cl_sidespeed.value * CL_KeyState (&in_moveleft, pnum, true);
|
||||
|
||||
if(in_xflip.ival) cmd->sidemove *= -1;
|
||||
|
||||
cmd->upmove += scale*cl_upspeed.value * CL_KeyState (&in_up, pnum, true);
|
||||
cmd->upmove -= scale*cl_upspeed.value * CL_KeyState (&in_down, pnum, true);
|
||||
cmd->upmove = cmd->upmove*oscale + nscale*cl_upspeed.value * (CL_KeyState (&in_up, pnum, true) - CL_KeyState (&in_down, pnum, true));
|
||||
|
||||
if (! (in_klook.state[pnum] & 1) )
|
||||
{
|
||||
cmd->forwardmove += scale*cl_forwardspeed.value * CL_KeyState (&in_forward, pnum, true);
|
||||
cmd->forwardmove -= scale*(*cl_backspeed.string?cl_backspeed.value:cl_forwardspeed.value) * CL_KeyState (&in_back, pnum, true);
|
||||
cmd->forwardmove = cmd->forwardmove*oscale + nscale*(cl_forwardspeed.value * CL_KeyState (&in_forward, pnum, true)) -
|
||||
((*cl_backspeed.string?cl_backspeed.value:cl_forwardspeed.value) * CL_KeyState (&in_back, pnum, true));
|
||||
}
|
||||
|
||||
if (!priortime) //only gather buttons if we've not had any this frame. this avoids jump feeling weird with prediction. FIXME: should probably still allow +attack to reduce latency
|
||||
CL_GatherButtons(cmd, pnum);
|
||||
}
|
||||
|
||||
|
@ -902,7 +898,7 @@ void CL_ClampPitch (int pnum)
|
|||
CL_FinishMove
|
||||
==============
|
||||
*/
|
||||
void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum)
|
||||
static void CL_FinishMove (usercmd_t *cmd, int pnum)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -923,9 +919,6 @@ void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum)
|
|||
|
||||
CL_GatherButtons(cmd, pnum);
|
||||
|
||||
// send milliseconds of time to apply the move
|
||||
cmd->msec = msecs;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
cmd->angles[i] = ((int)(cl.playerview[pnum].viewangles[i]*65536.0/360)&65535);
|
||||
|
||||
|
@ -1017,7 +1010,6 @@ void CL_UpdatePrydonCursor(usercmd_t *from, int pnum)
|
|||
#ifdef NQPROT
|
||||
void CLNQ_SendMove (usercmd_t *cmd, int pnum, sizebuf_t *buf)
|
||||
{
|
||||
static float oldgametime;
|
||||
int i;
|
||||
|
||||
if (cls.demoplayback!=DPB_NONE)
|
||||
|
@ -1036,8 +1028,7 @@ void CLNQ_SendMove (usercmd_t *cmd, int pnum, sizebuf_t *buf)
|
|||
|
||||
if (cls.protocol_nq >= CPNQ_DP7)
|
||||
{
|
||||
extern cvar_t cl_nopred;
|
||||
if (cl_nopred.ival)
|
||||
if (!cl_movement.ival)
|
||||
MSG_WriteLong(buf, 0);
|
||||
else
|
||||
MSG_WriteLong(buf, cl.movesequence);
|
||||
|
@ -1045,9 +1036,7 @@ void CLNQ_SendMove (usercmd_t *cmd, int pnum, sizebuf_t *buf)
|
|||
else if (cls.fteprotocolextensions2 & PEXT2_PREDINFO)
|
||||
MSG_WriteShort(buf, cl.movesequence&0xffff);
|
||||
|
||||
MSG_WriteFloat (buf, cl.gametime); // so server can get ping times
|
||||
cmd->msec = bound(0, cl.gametime - oldgametime, .25)*1000;
|
||||
oldgametime = cl.gametime;
|
||||
MSG_WriteFloat (buf, cmd->fservertime); // use latest time. because ping reports!
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
|
@ -1108,19 +1097,19 @@ void CLNQ_SendCmd(sizebuf_t *buf)
|
|||
cl.outframes[i].latency = -1;
|
||||
cl.outframes[i].server_message_num = cl.validsequence;
|
||||
cl.outframes[i].cmd_sequence = cl.movesequence;
|
||||
cl.outframes[i].sentgametime = cl.movesequence_time;
|
||||
|
||||
for (seat = 0; seat < cl.splitclients; seat++)
|
||||
{
|
||||
cmd = &cl.outframes[i].cmd[seat];
|
||||
*cmd = independantphysics[seat];
|
||||
cmd->lightlevel = 0;
|
||||
*cmd = cl_pendingcmd[seat];
|
||||
cmd->fservertime = cl.movesequence_time;
|
||||
// cmd->msec = (cl.time - cl.outframes[(i-1)&UPDATE_MASK].sentgametime)*1000;
|
||||
#ifdef CSQC_DAT
|
||||
CSQC_Input_Frame(seat, cmd);
|
||||
#endif
|
||||
memset(&independantphysics[seat], 0, sizeof(independantphysics[seat]));
|
||||
}
|
||||
|
||||
|
||||
//inputs are only sent once we receive an entity.
|
||||
if (cls.signon == 4)
|
||||
{
|
||||
|
@ -1148,7 +1137,7 @@ void Name_Callback(struct cvar_s *var, char *oldvalue)
|
|||
}
|
||||
#endif
|
||||
|
||||
float CL_FilterTime (double time, float wantfps, qboolean ignoreserver) //now returns the extra time not taken in this slot. Note that negative 1 means uncapped.
|
||||
float CL_FilterTime (double time, float wantfps, float limit, qboolean ignoreserver) //now returns the extra time not taken in this slot. Note that negative 1 means uncapped.
|
||||
{
|
||||
float fps, fpscap;
|
||||
|
||||
|
@ -1184,8 +1173,8 @@ float CL_FilterTime (double time, float wantfps, qboolean ignoreserver) //now re
|
|||
return 0;
|
||||
|
||||
//clamp it if we have over 1.5 frame banked somehow
|
||||
if (time - (1000 / fps) > (1000 / fps)*1.5)
|
||||
return (1000 / fps) * 1.5;
|
||||
if (limit && time - (1000 / fps) > (1000 / fps)*limit)
|
||||
return (1000 / fps) * limit;
|
||||
|
||||
//report how much spare time the caller now has
|
||||
return time - (1000 / fps);
|
||||
|
@ -1325,7 +1314,7 @@ int CL_IndepPhysicsThread(void *param)
|
|||
while(runningindepphys)
|
||||
{
|
||||
time = Sys_DoubleTime();
|
||||
spare = CL_FilterTime((time - lasttime)*1000, cl_netfps.value, false);
|
||||
spare = CL_FilterTime((time - lasttime)*1000, cl_netfps.value, 1.5, false);
|
||||
if (spare)
|
||||
{
|
||||
time -= spare/1000.0f;
|
||||
|
@ -1539,13 +1528,13 @@ qboolean CLQ2_SendCmd (sizebuf_t *buf)
|
|||
|
||||
i = cls.netchan.outgoing_sequence & UPDATE_MASK;
|
||||
cmd = &cl.outframes[i].cmd[seat];
|
||||
*cmd = independantphysics[seat];
|
||||
*cmd = cl_pendingcmd[seat];
|
||||
|
||||
cmd->lightlevel = (lightlev>255)?255:lightlev;
|
||||
|
||||
cl.outframes[i].senttime = realtime;
|
||||
cl.outframes[i].latency = -1;
|
||||
memset(&independantphysics[seat], 0, sizeof(independantphysics[0]));
|
||||
memset(&cl_pendingcmd[seat], 0, sizeof(cl_pendingcmd[seat]));
|
||||
|
||||
if (cmd->buttons)
|
||||
cmd->buttons |= 128; //fixme: this isn't really what's meant by the anykey.
|
||||
|
@ -1613,14 +1602,14 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend)
|
|||
}
|
||||
|
||||
cmd = &cl.outframes[curframe].cmd[plnum];
|
||||
*cmd = independantphysics[plnum];
|
||||
*cmd = cl_pendingcmd[plnum];
|
||||
|
||||
cmd->lightlevel = 0;
|
||||
#ifdef CSQC_DAT
|
||||
if (!runningindepphys)
|
||||
CSQC_Input_Frame(plnum, cmd);
|
||||
#endif
|
||||
memset(&independantphysics[plnum], 0, sizeof(independantphysics[plnum]));
|
||||
memset(&cl_pendingcmd[plnum], 0, sizeof(cl_pendingcmd[plnum]));
|
||||
}
|
||||
|
||||
cmd = &cl.outframes[curframe].cmd[0];
|
||||
|
@ -1706,9 +1695,10 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
static int dropcount = 0;
|
||||
static double msecs;
|
||||
static double msecsround;
|
||||
int msecstouse;
|
||||
qboolean dontdrop=false;
|
||||
float usetime;
|
||||
float usetime; //how many msecs we can use for the new frame
|
||||
int msecstouse; //usetime truncated to network precision (how much we'll actually eat)
|
||||
float framemsecs; //how long we're saying the input frame should be (differs from realtime with nq as we want to send frames reguarly, but note this might end up with funny-duration frames).
|
||||
|
||||
clcmdbuf_t *next;
|
||||
|
||||
|
@ -1745,6 +1735,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
}
|
||||
for (plnum = 0; plnum < cl.splitclients; plnum++)
|
||||
{
|
||||
vec3_t mousemovements;
|
||||
playerview_t *pv = &cl.playerview[plnum];
|
||||
cmd = &cl.outframes[i].cmd[plnum];
|
||||
|
||||
|
@ -1754,24 +1745,24 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
msecs = 50;
|
||||
cmd->msec = msecs;
|
||||
msecs -= cmd->msec;
|
||||
independantphysics[0].msec = 0;
|
||||
cl_pendingcmd[plnum].msec = 0;
|
||||
|
||||
CL_AdjustAngles (plnum, frametime);
|
||||
// get basic movement from keyboard
|
||||
CL_BaseMove (cmd, plnum, 1, 1);
|
||||
CL_BaseMove (cmd, plnum, 0, 1);
|
||||
|
||||
// allow mice or other external controllers to add to the move
|
||||
IN_Move (mousemovements[plnum], plnum, frametime);
|
||||
independantphysics[plnum].forwardmove += mousemovements[plnum][0];
|
||||
independantphysics[plnum].sidemove += mousemovements[plnum][1];
|
||||
independantphysics[plnum].upmove += mousemovements[plnum][2];
|
||||
VectorClear(mousemovements[plnum]);
|
||||
VectorClear(mousemovements);
|
||||
IN_Move (mousemovements, plnum, frametime);
|
||||
cl_pendingcmd[plnum].forwardmove += mousemovements[0];
|
||||
cl_pendingcmd[plnum].sidemove += mousemovements[1];
|
||||
cl_pendingcmd[plnum].upmove += mousemovements[2];
|
||||
|
||||
// if we are spectator, try autocam
|
||||
if (pv->spectator)
|
||||
Cam_Track(pv, cmd);
|
||||
|
||||
CL_FinishMove(cmd, cmd->msec, plnum);
|
||||
CL_FinishMove(cmd, plnum);
|
||||
|
||||
Cam_FinishMove(pv, cmd);
|
||||
|
||||
|
@ -1812,11 +1803,32 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
buf.data = data;
|
||||
buf.prim = cls.netchan.message.prim;
|
||||
|
||||
#ifdef IRCCONNECT
|
||||
if (cls.netchan.remote_address.type != NA_IRC)
|
||||
#endif
|
||||
if (cls.protocol == CP_NETQUAKE && cl.time && !cl.paused)
|
||||
{
|
||||
if (cl.movesequence_time > cl.time + 0.5)
|
||||
cl.movesequence_time = cl.time + 0.5; //shouldn't really happen
|
||||
if (cl.movesequence_time < cl.time - 0.5)
|
||||
cl.movesequence_time = cl.time - 0.5; //shouldn't really happen
|
||||
framemsecs = (cl.time - cl.movesequence_time)*1000;
|
||||
|
||||
wantfps = cl_netfps.value;
|
||||
usetime = CL_FilterTime(framemsecs, wantfps, 1.5, false);
|
||||
if (usetime > 0)
|
||||
{
|
||||
usetime = framemsecs - usetime;
|
||||
fullsend = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
usetime = framemsecs - usetime;
|
||||
fullsend = false;
|
||||
}
|
||||
framemsecs = usetime;
|
||||
}
|
||||
else
|
||||
{
|
||||
msecs += frametime*1000;
|
||||
|
||||
// Con_Printf("%f\n", msecs);
|
||||
|
||||
wantfps = cl_netfps.value;
|
||||
|
@ -1847,7 +1859,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
if (!runningindepphys && (cl_netfps.value > 0 || !fullsend))
|
||||
{
|
||||
float spare;
|
||||
spare = CL_FilterTime(msecs, wantfps, false);
|
||||
spare = CL_FilterTime(msecs, wantfps, (cls.protocol == CP_NETQUAKE?0:1.5), false);
|
||||
usetime = msecsround + (msecs - spare);
|
||||
msecstouse = (int)usetime;
|
||||
if (!spare)
|
||||
|
@ -1875,46 +1887,52 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
else if (msecstouse > 50)
|
||||
msecstouse &= ~1; // align to 2
|
||||
|
||||
if (msecstouse < 0) //FIXME
|
||||
if (msecstouse <= 0) //FIXME
|
||||
fullsend = false;
|
||||
if (usetime <= 0)
|
||||
return; //infinite frame times = weirdness.
|
||||
|
||||
cl.movesequence_time = cl.time;
|
||||
framemsecs = msecstouse;
|
||||
|
||||
if (cls.protocol == CP_NETQUAKE)
|
||||
framemsecs = 0;
|
||||
}
|
||||
|
||||
#ifdef HLCLIENT
|
||||
if (!CLHL_BuildUserInput(msecstouse, &independantphysics[0]))
|
||||
#endif
|
||||
for (plnum = 0; plnum < cl.splitclients; plnum++)
|
||||
{
|
||||
// CL_BaseMove (&independantphysics[plnum], plnum, (msecstouse - independantphysics[plnum].msec), wantfps);
|
||||
vec3_t mousemovements;
|
||||
CL_AdjustAngles (plnum, frametime);
|
||||
IN_Move (mousemovements[plnum], plnum, frametime);
|
||||
VectorClear(mousemovements);
|
||||
IN_Move (mousemovements, plnum, frametime);
|
||||
CL_ClampPitch(plnum);
|
||||
independantphysics[plnum].forwardmove += mousemovements[plnum][0];
|
||||
independantphysics[plnum].sidemove += mousemovements[plnum][1];
|
||||
independantphysics[plnum].upmove += mousemovements[plnum][2];
|
||||
VectorClear(mousemovements[plnum]);
|
||||
cl_pendingcmd[plnum].forwardmove += mousemovements[0]; //FIXME: this will get nuked by CL_BaseMove.
|
||||
cl_pendingcmd[plnum].sidemove += mousemovements[1];
|
||||
cl_pendingcmd[plnum].upmove += mousemovements[2];
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
independantphysics[plnum].angles[i] = ((int)(cl.playerview[plnum].viewangles[i]*65536.0/360)&65535);
|
||||
cl_pendingcmd[plnum].angles[i] = ((int)(cl.playerview[plnum].viewangles[i]*65536.0/360)&65535);
|
||||
|
||||
if (!independantphysics[plnum].msec)
|
||||
CL_BaseMove (&cl_pendingcmd[plnum], plnum, cl_pendingcmd[plnum].msec, framemsecs);
|
||||
if (!cl_pendingcmd[plnum].msec)
|
||||
{
|
||||
CL_BaseMove (&independantphysics[plnum], plnum, (msecstouse - independantphysics[plnum].msec), wantfps);
|
||||
CL_FinishMove(&independantphysics[plnum], msecstouse, plnum);
|
||||
|
||||
CL_FinishMove(&cl_pendingcmd[plnum], plnum);
|
||||
Cbuf_Waited(); //its okay to stop waiting now
|
||||
}
|
||||
cl_pendingcmd[plnum].msec = framemsecs;
|
||||
|
||||
// if we are spectator, try autocam
|
||||
// if (cl.spectator)
|
||||
Cam_Track(&cl.playerview[plnum], &independantphysics[plnum]);
|
||||
Cam_FinishMove(&cl.playerview[plnum], &independantphysics[plnum]);
|
||||
independantphysics[plnum].msec = usetime;
|
||||
Cam_Track(&cl.playerview[plnum], &cl_pendingcmd[plnum]);
|
||||
Cam_FinishMove(&cl.playerview[plnum], &cl_pendingcmd[plnum]);
|
||||
|
||||
//HACK: 1000/77 = 12.98. nudge it just under so we never appear to be using 83fps at 77fps (which can trip cheat detection in mods that expect 72 fps when many servers are configured for 77)
|
||||
//so lets just never use 12.
|
||||
if (fullsend && (independantphysics[plnum].msec > 12.9 && independantphysics[plnum].msec < 13) && cls.maxfps == 77)
|
||||
independantphysics[plnum].msec = 13;
|
||||
if (fullsend && (cl_pendingcmd[plnum].msec > 12.9 && cl_pendingcmd[plnum].msec < 13) && cls.maxfps == 77)
|
||||
cl_pendingcmd[plnum].msec = 13;
|
||||
}
|
||||
|
||||
//the main loop isn't allowed to send
|
||||
|
@ -1977,10 +1995,12 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
}
|
||||
cursor_active = false;
|
||||
|
||||
cmd = &independantphysics[0];
|
||||
for (plnum = 0; plnum < cl.splitclients; plnum++)
|
||||
{
|
||||
cmd = &cl_pendingcmd[plnum];
|
||||
if (((cls.fteprotocolextensions2 & PEXT2_PRYDONCURSOR)||(cls.protocol == CP_NETQUAKE && cls.protocol_nq >= CPNQ_DP6)) &&
|
||||
(*cl_prydoncursor.string && cl_prydoncursor.ival >= 0) && cls.state == ca_active)
|
||||
CL_UpdatePrydonCursor(cmd, 0);
|
||||
CL_UpdatePrydonCursor(cmd, plnum);
|
||||
else
|
||||
{
|
||||
Vector2Clear(cmd->cursor_screen);
|
||||
|
@ -1988,13 +2008,16 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
VectorClear(cmd->cursor_impact);
|
||||
cmd->cursor_entitynumber = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cl.movesequence_time += framemsecs/1000.0;
|
||||
switch (cls.protocol)
|
||||
{
|
||||
#ifdef NQPROT
|
||||
case CP_NETQUAKE:
|
||||
msecs -= (double)msecstouse;
|
||||
CLNQ_SendCmd (&buf);
|
||||
dontdrop = true;
|
||||
break;
|
||||
#endif
|
||||
case CP_QUAKEWORLD:
|
||||
|
@ -2010,8 +2033,8 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
#ifdef Q3CLIENT
|
||||
case CP_QUAKE3:
|
||||
msecs -= (double)msecstouse;
|
||||
CLQ3_SendCmd(&independantphysics[0]);
|
||||
memset(&independantphysics[0], 0, sizeof(independantphysics[0]));
|
||||
CLQ3_SendCmd(&cl_pendingcmd[0]);
|
||||
memset(&cl_pendingcmd[0], 0, sizeof(cl_pendingcmd[0]));
|
||||
|
||||
//don't bank too much, because that results in banking speedcheats
|
||||
if (msecs > 200)
|
||||
|
@ -2022,17 +2045,22 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
Host_EndGame("Invalid protocol in CL_SendCmd: %i", cls.protocol);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i = cl.movesequence & UPDATE_MASK;
|
||||
cmd = &cl.outframes[i].cmd[0];
|
||||
|
||||
if (cls.demorecording)
|
||||
CL_WriteDemoCmd(cmd);
|
||||
CL_WriteDemoCmd(&cl.outframes[cl.movesequence & UPDATE_MASK].cmd[0]);
|
||||
|
||||
// Con_DPrintf("generated sequence %i\n", cl.movesequence);
|
||||
cl.movesequence++;
|
||||
|
||||
//clear enough of the pending command for the next frame.
|
||||
for (plnum = 0; plnum < cl.splitclients; plnum++)
|
||||
{
|
||||
cl_pendingcmd[plnum].msec = 0;
|
||||
cl_pendingcmd[plnum].impulse = 0;
|
||||
cl_pendingcmd[plnum].buttons = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IRCCONNECT
|
||||
if (cls.netchan.remote_address.type == NA_IRC)
|
||||
{
|
||||
|
@ -2043,7 +2071,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
else
|
||||
{
|
||||
// don't count this message when calculating PL
|
||||
cl.outframes[i].latency = -3;
|
||||
cl.outframes[cls.netchan.outgoing_sequence&UPDATE_MASK].latency = -3;
|
||||
// drop this message
|
||||
cls.netchan.outgoing_sequence++;
|
||||
dropcount++;
|
||||
|
@ -2157,6 +2185,10 @@ void CL_InitInput (void)
|
|||
Cvar_Register (&cl_sparemsec, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_run, inputnetworkcvargroup);
|
||||
|
||||
#ifdef NQPROT
|
||||
Cvar_Register (&cl_movement, inputnetworkcvargroup);
|
||||
#endif
|
||||
|
||||
Cvar_Register (&cl_smartjump, inputnetworkcvargroup);
|
||||
|
||||
Cvar_Register (&cl_prydoncursor, inputnetworkcvargroup);
|
||||
|
|
|
@ -101,10 +101,10 @@ cvar_t record_flush = CVARD("record_flush", "0", "If set, explicitly flushes dem
|
|||
cvar_t cl_demospeed = CVARF("cl_demospeed", "1", 0);
|
||||
cvar_t cl_demoreel = CVARFD("cl_demoreel", "0", CVAR_SAVE, "When enabled, the engine will begin playing a demo loop on startup.");
|
||||
|
||||
cvar_t cl_loopbackprotocol = CVARD("cl_loopbackprotocol", "qw", "Which protocol to use for single-player/the internal client. Should be one of: qw, qwid, nqid, nq, fitz, dp6, dp7. If empty, will use qw protocols for qw mods, and nq protocols for nq mods.");
|
||||
cvar_t cl_loopbackprotocol = CVARD("cl_loopbackprotocol", "qw", "Which protocol to use for single-player/the internal client. Should be one of: qw, qwid, nqid, nq, fitz, bjp3, dp6, dp7, auto. If 'auto', will use qw protocols for qw mods, and nq protocols for nq mods.");
|
||||
|
||||
|
||||
cvar_t cl_threadedphysics = CVAR("cl_threadedphysics", "0");
|
||||
cvar_t cl_threadedphysics = CVARD("cl_threadedphysics", "0", "When set, client input frames are generated and sent on a worker thread");
|
||||
|
||||
#ifdef QUAKESPYAPI
|
||||
cvar_t localid = SCVAR("localid", "");
|
||||
|
@ -124,8 +124,8 @@ cvar_t password = CVARAF("password", "", "pq_password", CVAR_USERINFO | CVAR_NOU
|
|||
cvar_t spectator = CVARF("spectator", "", CVAR_USERINFO);
|
||||
cvar_t name = CVARFC("name", "Player", CVAR_ARCHIVE | CVAR_USERINFO, Name_Callback);
|
||||
cvar_t team = CVARF("team", "", CVAR_ARCHIVE | CVAR_USERINFO);
|
||||
cvar_t skin = CVARF("skin", "", CVAR_ARCHIVE | CVAR_USERINFO);
|
||||
cvar_t model = CVARF("model", "", CVAR_ARCHIVE | CVAR_USERINFO);
|
||||
cvar_t skin = CVARAF("skin", "", "_cl_playerskin", CVAR_ARCHIVE | CVAR_USERINFO);
|
||||
cvar_t model = CVARAF("model", "", "_cl_playermodel", CVAR_ARCHIVE | CVAR_USERINFO);
|
||||
cvar_t topcolor = CVARF("topcolor", "", CVAR_ARCHIVE | CVAR_USERINFO);
|
||||
cvar_t bottomcolor = CVARF("bottomcolor", "", CVAR_ARCHIVE | CVAR_USERINFO);
|
||||
cvar_t rate = CVARFD("rate", "30000"/*"6480"*/, CVAR_ARCHIVE | CVAR_USERINFO, "A rough measure of the bandwidth to try to use while playing. Too high a value may result in 'buffer bloat'.");
|
||||
|
@ -422,7 +422,7 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr)
|
|||
|
||||
connectinfo.time = realtime; // for retransmit requests
|
||||
|
||||
Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP NEHAHRABJP2 NEHAHRABJP3 QUAKE\\challenge\\%s", 255, 255, 255, 255, challenge);
|
||||
Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\%s\\name\\%s", 255, 255, 255, 255, challenge, name.string);
|
||||
|
||||
NET_SendPacket (NS_CLIENT, strlen(data), data, adr);
|
||||
|
||||
|
@ -714,6 +714,7 @@ void CL_CheckForResend (void)
|
|||
qboolean keeptrying = true;
|
||||
char *host;
|
||||
extern int r_blockvidrestart;
|
||||
const char *lbp;
|
||||
|
||||
#ifndef CLIENTONLY
|
||||
if (!cls.state && (!connectinfo.trying || sv.state != ss_clustermode) && sv.state)
|
||||
|
@ -753,24 +754,28 @@ void CL_CheckForResend (void)
|
|||
#endif
|
||||
default:
|
||||
cl.movesequence = 0;
|
||||
if (!strcmp(cl_loopbackprotocol.string, "qw") || progstype == PROG_H2)
|
||||
lbp = cl_loopbackprotocol.string;
|
||||
if (!strcmp(lbp, "") || !strcmp(lbp, "qw") || progstype == PROG_H2)
|
||||
{ //qw with all supported extensions -default
|
||||
//for hexen2 we always force fte's native qw protocol. other protocols won't cut it.
|
||||
connectinfo.protocol = CP_QUAKEWORLD;
|
||||
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
|
||||
connectinfo.fteext1 = Net_PextMask(1, false);
|
||||
connectinfo.fteext2 = Net_PextMask(2, false);
|
||||
connectinfo.protocol = CP_QUAKEWORLD;
|
||||
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
|
||||
}
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "qwid") || !strcmp(cl_loopbackprotocol.string, "idqw"))
|
||||
{
|
||||
else if (!strcmp(lbp, "qwid") || !strcmp(cl_loopbackprotocol.string, "idqw"))
|
||||
{ //for recording .qwd files in any client
|
||||
connectinfo.protocol = CP_QUAKEWORLD;
|
||||
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
|
||||
connectinfo.fteext1 = 0;
|
||||
connectinfo.fteext2 = 0;
|
||||
}
|
||||
#ifdef Q3CLIENT
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "q3"))
|
||||
else if (!strcmp(lbp, "q3"))
|
||||
cls.protocol = CP_QUAKE3;
|
||||
#endif
|
||||
#ifdef NQPROT
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "random"))
|
||||
else if (!strcmp(lbp, "random"))
|
||||
{ //for debugging.
|
||||
if (rand() & 1)
|
||||
{
|
||||
|
@ -785,33 +790,33 @@ void CL_CheckForResend (void)
|
|||
connectinfo.fteext2 = Net_PextMask(2, false);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "fitz") || !strcmp(cl_loopbackprotocol.string, "666") || !strcmp(cl_loopbackprotocol.string, "999"))
|
||||
{
|
||||
else if (!strcmp(lbp, "fitz") || !strcmp(lbp, "666") || !strcmp(lbp, "999"))
|
||||
{ //we don't really distinguish between fitz and rmq protocols. we just use 999 with bigcoords and 666 othewise.
|
||||
connectinfo.protocol = CP_NETQUAKE;
|
||||
connectinfo.subprotocol = CPNQ_FITZ666;
|
||||
}
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "bjp3") || !strcmp(cl_loopbackprotocol.string, "bjp"))
|
||||
else if (!strcmp(lbp, "bjp3") || !strcmp(lbp, "bjp"))
|
||||
{
|
||||
connectinfo.protocol = CP_NETQUAKE;
|
||||
connectinfo.subprotocol = CPNQ_BJP3;
|
||||
}
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "nq"))
|
||||
else if (!strcmp(lbp, "nq"))
|
||||
{
|
||||
connectinfo.protocol = CP_NETQUAKE;
|
||||
connectinfo.subprotocol = CPNQ_ID;
|
||||
proquakeangles = true;
|
||||
}
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "nqid") || !strcmp(cl_loopbackprotocol.string, "idnq"))
|
||||
else if (!strcmp(lbp, "nqid") || !strcmp(lbp, "idnq"))
|
||||
{
|
||||
connectinfo.protocol = CP_NETQUAKE;
|
||||
connectinfo.subprotocol = CPNQ_ID;
|
||||
}
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "dp6") || !strcmp(cl_loopbackprotocol.string, "dpp6"))
|
||||
else if (!strcmp(lbp, "dp6") || !strcmp(lbp, "dpp6"))
|
||||
{
|
||||
connectinfo.protocol = CP_NETQUAKE;
|
||||
connectinfo.subprotocol = CPNQ_DP6;
|
||||
}
|
||||
else if (!strcmp(cl_loopbackprotocol.string, "dp7") || !strcmp(cl_loopbackprotocol.string, "dpp7"))
|
||||
else if (!strcmp(lbp, "dp7") || !strcmp(lbp, "dpp7"))
|
||||
{
|
||||
connectinfo.protocol = CP_NETQUAKE;
|
||||
connectinfo.subprotocol = CPNQ_DP7;
|
||||
|
@ -820,7 +825,8 @@ void CL_CheckForResend (void)
|
|||
{
|
||||
connectinfo.protocol = CP_NETQUAKE;
|
||||
connectinfo.subprotocol = CPNQ_FITZ666;
|
||||
//FIXME: pext
|
||||
connectinfo.fteext1 = Net_PextMask(1, true);
|
||||
connectinfo.fteext2 = Net_PextMask(2, true);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
|
@ -932,7 +938,7 @@ void CL_CheckForResend (void)
|
|||
}
|
||||
else
|
||||
CL_ConnectToDarkPlaces("", &connectinfo.adr);
|
||||
connectinfo.trying = false;
|
||||
// connectinfo.trying = false;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -1904,6 +1910,9 @@ void CL_Color_f (void)
|
|||
|
||||
qboolean server_owns_colour;
|
||||
|
||||
char *t;
|
||||
char *b;
|
||||
|
||||
if (Cmd_Argc() == 1)
|
||||
{
|
||||
char *t = Info_ValueForKey (cls.userinfo[pnum], "topcolor");
|
||||
|
@ -1923,13 +1932,14 @@ void CL_Color_f (void)
|
|||
server_owns_colour = false;
|
||||
|
||||
|
||||
if (Cmd_Argc() == 2)
|
||||
top = bottom = CL_ParseColour(Cmd_Argv(1));
|
||||
else
|
||||
{
|
||||
top = CL_ParseColour(Cmd_Argv(1));
|
||||
bottom = CL_ParseColour(Cmd_Argv(2));
|
||||
}
|
||||
t = Cmd_Argv(1);
|
||||
b = (Cmd_Argc()==2)?t:Cmd_Argv(2);
|
||||
if (!strcmp(t, "-1"))
|
||||
t = Info_ValueForKey (cls.userinfo[pnum], "topcolor");
|
||||
top = CL_ParseColour(t);
|
||||
if (!strcmp(b, "-1"))
|
||||
b = Info_ValueForKey (cls.userinfo[pnum], "bottomcolor");
|
||||
bottom = CL_ParseColour(b);
|
||||
|
||||
Q_snprintfz (num, sizeof(num), (top&0xff000000)?"0x%06x":"%i", top & 0xffffff);
|
||||
if (top == 0)
|
||||
|
@ -5419,7 +5429,7 @@ double Host_Frame (double time)
|
|||
)
|
||||
{
|
||||
// realtime += spare/1000; //don't use it all!
|
||||
double newspare = CL_FilterTime((spare/1000 + realtime - oldrealtime)*1000, maxfps, maxfpsignoreserver);
|
||||
double newspare = CL_FilterTime((spare/1000 + realtime - oldrealtime)*1000, maxfps, 1.5, maxfpsignoreserver);
|
||||
if (!newspare)
|
||||
{
|
||||
while(COM_DoWork(0, false))
|
||||
|
|
|
@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "quakedef.h"
|
||||
#include "cl_ignore.h"
|
||||
#include "shader.h"
|
||||
|
||||
void CL_GetNumberedEntityInfo (int num, float *org, float *ang);
|
||||
void CLDP_ParseDarkPlaces5Entities(void);
|
||||
|
@ -3736,8 +3737,8 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
|
|||
CL_SendClientCommand(true, "color %i %i\n", topcolor.ival, bottomcolor.ival);
|
||||
if (cl.haveserverinfo)
|
||||
Info_Enumerate(cls.userinfo[0], NULL, CLNQ_SendInitialUserInfo);
|
||||
else if (CPNQ_IS_DP) //dp needs a couple of extras to work properly. don't send them on other servers because that generally results in error messages.
|
||||
{
|
||||
else if (CPNQ_IS_DP)
|
||||
{ //dp needs a couple of extras to work properly in certain cases. don't send them on other servers because that generally results in error messages.
|
||||
CL_SendClientCommand(true, "rate %s", rate.string);
|
||||
CL_SendClientCommand(true, "playermodel %s", model.string);
|
||||
CL_SendClientCommand(true, "playerskin %s", skin.string);
|
||||
|
@ -4170,9 +4171,7 @@ static void CLQ2_ParseConfigString (void)
|
|||
Q_strncpyz (cl.levelname, s, sizeof(cl.levelname));
|
||||
}
|
||||
else if (i == Q2CS_SKY)
|
||||
{
|
||||
Q_strncpyz (cl.skyname, s, sizeof(cl.skyname));
|
||||
}
|
||||
R_SetSky(s);
|
||||
else if (i == Q2CS_SKYAXIS)
|
||||
{
|
||||
s = COM_Parse(s);
|
||||
|
@ -4819,15 +4818,13 @@ void CL_ParseClientdata (void)
|
|||
oldparsecountmod = cl.oldparsecount & UPDATE_MASK;
|
||||
}
|
||||
cl.parsecount = i;
|
||||
i &= UPDATE_MASK;
|
||||
parsecountmod = i;
|
||||
parsecountmod = i&UPDATE_MASK;
|
||||
parsecounttime = realtime;//cl.outframes[i].senttime;
|
||||
|
||||
if (cls.protocol == CP_QUAKEWORLD)
|
||||
CL_AckedInputFrame(cls.netchan.incoming_sequence, cl.parsecount, false);
|
||||
}
|
||||
|
||||
#include "shader.h"
|
||||
static qboolean CLQ2_PlayerSkinIsOkay(skinid_t id)
|
||||
{
|
||||
skinfile_t *sk = Mod_LookupSkin(id);
|
||||
|
@ -5026,10 +5023,10 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player)
|
|||
{
|
||||
Cam_Unlock(&cl.playerview[i]);
|
||||
}
|
||||
CL_CheckServerInfo();
|
||||
}
|
||||
|
||||
// Update the rules since spectators can bypass everything but players can't
|
||||
if (ospec != player->spectator)
|
||||
else if (ospec != player->spectator)
|
||||
CL_CheckServerInfo();
|
||||
|
||||
Skin_FlushPlayers();
|
||||
|
@ -7498,8 +7495,6 @@ void CLNQ_ParseServerMessage (void)
|
|||
else if (cl_shownet.value == 2)
|
||||
Con_Printf ("------------------\n");
|
||||
|
||||
|
||||
CL_ParseClientdata ();
|
||||
//
|
||||
// parse the message
|
||||
//
|
||||
|
@ -7648,6 +7643,7 @@ void CLNQ_ParseServerMessage (void)
|
|||
cls.signon = 4;
|
||||
CLNQ_SignonReply ();
|
||||
}
|
||||
CL_ParseClientdata ();
|
||||
CLFTE_ParseEntities();
|
||||
break;
|
||||
case svcfte_spawnstatic2:
|
||||
|
@ -7670,6 +7666,8 @@ void CLNQ_ParseServerMessage (void)
|
|||
break;
|
||||
|
||||
case svc_time:
|
||||
CL_ParseClientdata ();
|
||||
|
||||
//fixme: move this stuff to a common place
|
||||
// cl.playerview[destsplit].oldfixangle = cl.playerview[destsplit].fixangle;
|
||||
// VectorCopy(cl.playerview[destsplit].fixangles, cl.playerview[destsplit].oldfixangles);
|
||||
|
@ -7933,8 +7931,7 @@ void CLNQ_ParseServerMessage (void)
|
|||
break;
|
||||
|
||||
case svcfitz_skybox:
|
||||
Q_strncpyz(cl.skyname, MSG_ReadString(), sizeof(cl.skyname));
|
||||
R_SetSky(cl.skyname);
|
||||
R_SetSky(MSG_ReadString());
|
||||
break;
|
||||
case svcfitz_bf:
|
||||
Cmd_ExecuteString("bf", RESTRICT_SERVER);
|
||||
|
|
|
@ -23,12 +23,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
cvar_t cl_predict_extrapolate = CVARD("cl_predict_extrapolate", "", "If 1, enables prediction based upon partial input frames which can change over time resulting in a swimmy feel but does not need to interpolate. If 0, prediction will stay in the past and thus use only completed frames. Interpolation will then be used to smooth movement.\nThis cvar only applies when video and input frames are independant (ie: cl_netfps is set).");
|
||||
cvar_t cl_predict_timenudge = CVARD("cl_predict_timenudge", "0", "A debug feature. You should normally leave this as 0. Nudges local player prediction into the future if positive (resulting in extrapolation), or into the past if negative (resulting in laggy interpolation). Value is in seconds, so small decimals are required. This cvar applies even if input frames are tied to video frames.");
|
||||
cvar_t cl_predict_smooth = CVARD("cl_lerp_smooth", "2", "If 2, will act as 1 when playing demos/singleplayer and otherwise act as if set to 0 (ie: deathmatch).\nIf 1, interpolation will run in the past, resulting in really smooth movement at the cost of latency (even on bunchy german ISDNs).\nIf 0, interpolation will be based upon packet arrival times and may judder due to packet loss.");
|
||||
cvar_t cl_nopred = CVAR("cl_nopred","0");
|
||||
cvar_t cl_nopred = CVARD("cl_nopred","0", "Disables clientside movement prediction.");
|
||||
cvar_t cl_pushlatency = CVAR("pushlatency","-999");
|
||||
|
||||
extern float pm_airaccelerate;
|
||||
|
||||
extern usercmd_t independantphysics[MAX_SPLITS];
|
||||
extern usercmd_t cl_pendingcmd[MAX_SPLITS];
|
||||
|
||||
#ifdef Q2CLIENT
|
||||
#define MAX_PARSE_ENTITIES 1024
|
||||
|
@ -297,10 +297,10 @@ static void CLQ2_PredictMovement (int seat) //q2 doesn't support split clients.
|
|||
VectorCopy (pm.s.origin, cl_predicted_origins[seat][frame]);
|
||||
}
|
||||
|
||||
if (independantphysics[seat].msec)
|
||||
if (cl_pendingcmd[seat].msec)
|
||||
{
|
||||
cmd = (q2usercmd_t*)&independantphysics[seat];
|
||||
cmd->msec = independantphysics[seat].msec;
|
||||
cmd = (q2usercmd_t*)&cl_pendingcmd[seat];
|
||||
cmd->msec = cl_pendingcmd[seat].msec;
|
||||
|
||||
pm.cmd = *cmd;
|
||||
Q2_Pmove (&pm);
|
||||
|
@ -891,12 +891,14 @@ void CL_PredictMovePNum (int seat)
|
|||
// netfps = fps;
|
||||
if (!*cl_predict_extrapolate.string)
|
||||
extrap = netfps < 30;
|
||||
if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP)
|
||||
extrap = true; //DP servers do a nasty thing where they send packets without any entities. This messes with our timings. Its much smoother to just always use extrapolation in this case (otherwise we'd have to backdate too much for prediction to do much).
|
||||
if (!extrap)
|
||||
{
|
||||
//interpolate. The input rate is completely smoothed out, at the cost of some latency.
|
||||
//You can still get juddering if the video rate doesn't match the monitor refresh rate (and isn't so high that it doesn't matter).
|
||||
//note that the code below will back-date input frames if the server acks too fast.
|
||||
simtime = realtime - (1/netfps);
|
||||
simtime = realtime - (1.0/netfps);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -907,7 +909,7 @@ void CL_PredictMovePNum (int seat)
|
|||
}
|
||||
|
||||
if (cls.demoplayback == DPB_QUAKEWORLD || pv->cam_state == CAM_EYECAM)
|
||||
simtime -= cls.latency;
|
||||
simtime -= cls.latency; //push back when playing demos.
|
||||
simtime += bound(-0.5, cl_predict_timenudge.value, 0.5);
|
||||
|
||||
pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD);
|
||||
|
@ -1209,8 +1211,8 @@ void CL_PredictMovePNum (int seat)
|
|||
cmdfrom = cmdto;
|
||||
|
||||
tostate = &framebuf[i++&1];
|
||||
if (independantphysics[seat].msec && !cls.demoplayback)
|
||||
indcmd = independantphysics[seat];
|
||||
if (cl_pendingcmd[seat].msec && !cls.demoplayback)
|
||||
indcmd = cl_pendingcmd[seat];
|
||||
else
|
||||
indcmd = *cmdto;
|
||||
cmdto = &indcmd;
|
||||
|
|
|
@ -46,28 +46,49 @@ void RSpeedShow(void)
|
|||
return;
|
||||
|
||||
memset(RSpNames, 0, sizeof(RSpNames));
|
||||
|
||||
RSPEED_TOTALREFRESH,
|
||||
RSPEED_CSQCPHYSICS,
|
||||
RSPEED_CSQCREDRAW,
|
||||
RSPEED_LINKENTITIES,
|
||||
RSPEED_WORLDNODE,
|
||||
RSPEED_DYNAMIC,
|
||||
RSPEED_OPAQUE,
|
||||
RSPEED_RTLIGHTS,
|
||||
RSPEED_TRANSPARENTS,
|
||||
RSPEED_PROTOCOL,
|
||||
RSPEED_PARTICLES,
|
||||
RSPEED_PARTICLESDRAW,
|
||||
RSPEED_PALETTEFLASHES,
|
||||
RSPEED_2D,
|
||||
RSPEED_SERVER,
|
||||
RSPEED_SETUP,
|
||||
RSPEED_SUBMIT,
|
||||
RSPEED_PRESENT,
|
||||
RSPEED_ACQUIRE,
|
||||
|
||||
|
||||
RSpNames[RSPEED_TOTALREFRESH] = "Total refresh";
|
||||
RSpNames[RSPEED_PROTOCOL] = "Protocol";
|
||||
RSpNames[RSPEED_CSQCPHYSICS] = " CSQC Physics";
|
||||
RSpNames[RSPEED_CSQCREDRAW] = " CSQC Drawing";
|
||||
RSpNames[RSPEED_LINKENTITIES] = " Entity setup";
|
||||
RSpNames[RSPEED_WORLDNODE] = " World walking";
|
||||
RSpNames[RSPEED_WORLD] = "World rendering";
|
||||
RSpNames[RSPEED_DYNAMIC] = " Lightmap updates";
|
||||
RSpNames[RSPEED_OPAQUE] = " Opaque Batches";
|
||||
RSpNames[RSPEED_RTLIGHTS] = " RT Lights";
|
||||
RSpNames[RSPEED_TRANSPARENTS] = " Transparent Batches";
|
||||
RSpNames[RSPEED_PARTICLES] = " Particle phys/sort";
|
||||
RSpNames[RSPEED_PARTICLESDRAW] = " Particle drawing";
|
||||
RSpNames[RSPEED_2D] = "2d elements";
|
||||
RSpNames[RSPEED_SERVER] = "Server";
|
||||
|
||||
RSpNames[RSPEED_DRAWENTITIES] = "Entity rendering";
|
||||
|
||||
RSpNames[RSPEED_2D] = " 2d Elements";
|
||||
RSpNames[RSPEED_PALETTEFLASHES] = " Palette flashes";
|
||||
RSpNames[RSPEED_STENCILSHADOWS] = "Stencil Shadows";
|
||||
|
||||
RSpNames[RSPEED_FULLBRIGHTS] = "World fullbrights";
|
||||
RSpNames[RSPEED_SETUP] = "Setup/Acquire";
|
||||
|
||||
RSpNames[RSPEED_SETUP] = "Acquire Wait";
|
||||
RSpNames[RSPEED_SUBMIT] = "submit/finish";
|
||||
RSpNames[RSPEED_PRESENT] = "present";
|
||||
RSpNames[RSPEED_ACQUIRE] = "acquire";
|
||||
RSpNames[RSPEED_PRESENT] = "Present";
|
||||
RSpNames[RSPEED_ACQUIRE] = "Acquire Request";
|
||||
|
||||
RSpNames[RSPEED_PROTOCOL] = "Client Protocol";
|
||||
RSpNames[RSPEED_SERVER] = "Server";
|
||||
|
||||
memset(RQntNames, 0, sizeof(RQntNames));
|
||||
RQntNames[RQUANT_MSECS] = "Microseconds";
|
||||
|
@ -91,8 +112,9 @@ void RSpeedShow(void)
|
|||
{
|
||||
for (i = 0; i < RSPEED_MAX; i++)
|
||||
{
|
||||
s = va("%g %-20s", samplerspeeds[i]/(float)frameinterval, RSpNames[i]);
|
||||
Draw_FunString(vid.width-strlen(s)*8, i*8, s);
|
||||
Draw_FunStringWidth(vid.width-20*8, i*8, RSpNames[i], 20*8, false, false);
|
||||
s = va("%g ", samplerspeeds[i]/(float)frameinterval);
|
||||
Draw_FunStringWidth(0, i*8, s, vid.width-20*8, true, false);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < RQUANT_MAX; i++)
|
||||
|
@ -102,7 +124,7 @@ void RSpeedShow(void)
|
|||
}
|
||||
if (r_speeds.ival > 1)
|
||||
{
|
||||
s = va("%f %-20s", (frameinterval*1000*1000.0f)/(samplerspeeds[RSPEED_TOTALREFRESH]+samplerspeeds[RSPEED_PRESENT]), "Framerate (refresh only)");
|
||||
s = va("%f %-20s", (frameinterval*1000*1000.0f)/samplerspeeds[RSPEED_TOTALREFRESH], "Framerate (refresh only)");
|
||||
Draw_FunString(vid.width-strlen(s)*8, (i+RSPEED_MAX)*8, s);
|
||||
}
|
||||
memcpy(rquant, savedsamplerquant, sizeof(rquant));
|
||||
|
@ -224,7 +246,7 @@ float scr_disabled_time;
|
|||
float oldsbar = 0;
|
||||
|
||||
cvar_t con_stayhidden = CVARFD("con_stayhidden", "0", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works");
|
||||
cvar_t show_fps = CVARF("show_fps", "0", CVAR_ARCHIVE);
|
||||
cvar_t show_fps = CVARFD("show_fps", "0", CVAR_ARCHIVE, "Displays the current framerate on-screen.\n1: framerate average over a second.\n2: Slowest frame over the last second (the game will play like shit if this is significantly lower than the average).\n3: Shows the rate of the fastest frame (not very useful).\n4: Shows the current frame's timings (this depends upon timer precision).\n5: Display a graph of how long it took to render each frame, large spikes are BAD BAD BAD.\n6: Displays the standard deviation of the frame times, if its greater than 3 then something is probably badly made, or you've a virus scanner running...\n7: Framegraph, for use with slower frames.");
|
||||
cvar_t show_fps_x = CVAR("show_fps_x", "-1");
|
||||
cvar_t show_fps_y = CVAR("show_fps_y", "-1");
|
||||
cvar_t show_clock = CVAR("cl_clock", "0");
|
||||
|
|
|
@ -234,6 +234,7 @@ typedef struct
|
|||
|
||||
int server_time;
|
||||
int client_time;
|
||||
float sentgametime; //nq timings are based upon server time echos.
|
||||
} outframe_t;
|
||||
|
||||
typedef struct
|
||||
|
@ -759,6 +760,7 @@ typedef struct
|
|||
// packetentity_t we got. If this is 0, we can't
|
||||
// render a frame yet
|
||||
int movesequence; // client->server frames
|
||||
float movesequence_time; // client->server frame timestamp (vs cl.time)
|
||||
|
||||
// int spectator;
|
||||
int autotrack_hint; //the latest hint from the mod, might be negative for invalid.
|
||||
|
@ -1166,7 +1168,7 @@ void CL_ClampPitch (int pnum);
|
|||
|
||||
int CL_ReadFromServer (void);
|
||||
void CL_WriteToServer (usercmd_t *cmd);
|
||||
void CL_BaseMove (usercmd_t *cmd, int pnum, float extra, float wantfps);
|
||||
void CL_BaseMove (usercmd_t *cmd, int pnum, float priortime, float extratime);
|
||||
|
||||
int Master_FindBestRoute(char *server, char *out, size_t outsize, int *directcost, int *chainedcost);
|
||||
|
||||
|
@ -1181,7 +1183,7 @@ void CL_UseIndepPhysics(qboolean allow);
|
|||
|
||||
void CL_FlushClientCommands(void);
|
||||
void VARGS CL_SendClientCommand(qboolean reliable, char *format, ...) LIKEPRINTF(2);
|
||||
float CL_FilterTime (double time, float wantfps, qboolean ignoreserver);
|
||||
float CL_FilterTime (double time, float wantfps, float limit, qboolean ignoreserver);
|
||||
int CL_RemoveClientCommands(char *command);
|
||||
void CL_AllowIndependantSendCmd(qboolean allow);
|
||||
|
||||
|
|
|
@ -232,6 +232,7 @@ void CL_GetNumberedEntityInfo (int num, float *org, float *ang)
|
|||
// FIXME: bmodel issues...
|
||||
}
|
||||
|
||||
#ifdef Q2SERVER
|
||||
void CLQ2_WriteDemoBaselines(sizebuf_t *buf)
|
||||
{
|
||||
int i;
|
||||
|
@ -270,6 +271,7 @@ void CLQ2_WriteDemoBaselines(sizebuf_t *buf)
|
|||
MSGQ2_WriteDeltaEntity(&nullstate, &es, buf, true, true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CLQ2_ClearState(void)
|
||||
{
|
||||
|
|
|
@ -2107,44 +2107,13 @@ qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height)
|
|||
|
||||
if (h.Compression) //RLE? BITFIELDS (gah)?
|
||||
return NULL;
|
||||
if (length < h.Size)
|
||||
return NULL; //truncated...
|
||||
|
||||
*width = h.Width;
|
||||
*height = h.Height;
|
||||
|
||||
if (h.NumofColorIndices != 0 || h.BitCount == 8) //8 bit
|
||||
{
|
||||
int x, y;
|
||||
unsigned int *data32;
|
||||
unsigned int pal[256];
|
||||
if (!h.NumofColorIndices)
|
||||
h.NumofColorIndices = (int)pow(2, h.BitCount);
|
||||
if (h.NumofColorIndices>256)
|
||||
return NULL;
|
||||
|
||||
data = buf+2;
|
||||
data += sizeof(h);
|
||||
|
||||
for (i = 0; i < h.NumofColorIndices; i++)
|
||||
{
|
||||
pal[i] = data[i*4+2] + (data[i*4+1]<<8) + (data[i*4+0]<<16) + (255/*data[i*4+3]*/<<24);
|
||||
}
|
||||
|
||||
buf += h.OffsetofBMPBits;
|
||||
data32 = BZ_Malloc(h.Width * h.Height*4);
|
||||
for (y = 0; y < h.Height; y++)
|
||||
{
|
||||
i = (h.Height-1-y) * (h.Width);
|
||||
for (x = 0; x < h.Width; x++)
|
||||
{
|
||||
data32[i] = pal[buf[x]];
|
||||
i++;
|
||||
}
|
||||
buf += h.Width;
|
||||
}
|
||||
|
||||
return (qbyte *)data32;
|
||||
}
|
||||
else if (h.BitCount == 4) //4 bit
|
||||
if (h.BitCount == 4) //4 bit
|
||||
{
|
||||
int x, y;
|
||||
unsigned int *data32;
|
||||
|
@ -2179,6 +2148,39 @@ qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height)
|
|||
|
||||
return (qbyte *)data32;
|
||||
}
|
||||
else if (h.BitCount == 8) //8 bit
|
||||
{
|
||||
int x, y;
|
||||
unsigned int *data32;
|
||||
unsigned int pal[256];
|
||||
if (!h.NumofColorIndices)
|
||||
h.NumofColorIndices = (int)pow(2, h.BitCount);
|
||||
if (h.NumofColorIndices>256)
|
||||
return NULL;
|
||||
|
||||
data = buf+2;
|
||||
data += sizeof(h);
|
||||
|
||||
for (i = 0; i < h.NumofColorIndices; i++)
|
||||
{
|
||||
pal[i] = data[i*4+2] + (data[i*4+1]<<8) + (data[i*4+0]<<16) + (255/*data[i*4+3]*/<<24);
|
||||
}
|
||||
|
||||
buf += h.OffsetofBMPBits;
|
||||
data32 = BZ_Malloc(h.Width * h.Height*4);
|
||||
for (y = 0; y < h.Height; y++)
|
||||
{
|
||||
i = (h.Height-1-y) * (h.Width);
|
||||
for (x = 0; x < h.Width; x++)
|
||||
{
|
||||
data32[i] = pal[buf[x]];
|
||||
i++;
|
||||
}
|
||||
buf += h.Width;
|
||||
}
|
||||
|
||||
return (qbyte *)data32;
|
||||
}
|
||||
else if (h.BitCount == 24) //24 bit... no 16?
|
||||
{
|
||||
int x, y;
|
||||
|
@ -2498,8 +2500,8 @@ static qboolean Image_ReadDDSFile(texid_t tex, unsigned int flags, char *fname,
|
|||
}
|
||||
else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('2'<<24))) //dx3 with premultiplied alpha
|
||||
{
|
||||
if (!(tex->flags & IF_PREMULTIPLYALPHA))
|
||||
return false;
|
||||
// if (!(tex->flags & IF_PREMULTIPLYALPHA))
|
||||
// return false;
|
||||
encoding = PTI_S3RGBA3;
|
||||
pad = 8;
|
||||
divsize = 4;
|
||||
|
@ -2507,8 +2509,8 @@ static qboolean Image_ReadDDSFile(texid_t tex, unsigned int flags, char *fname,
|
|||
}
|
||||
else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('3'<<24)))
|
||||
{
|
||||
if (tex->flags & IF_PREMULTIPLYALPHA)
|
||||
return false;
|
||||
// if (tex->flags & IF_PREMULTIPLYALPHA)
|
||||
// return false;
|
||||
encoding = PTI_S3RGBA3;
|
||||
pad = 8;
|
||||
divsize = 4;
|
||||
|
@ -2517,7 +2519,8 @@ static qboolean Image_ReadDDSFile(texid_t tex, unsigned int flags, char *fname,
|
|||
else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('4'<<24))) //dx5 with premultiplied alpha
|
||||
{
|
||||
// if (!(tex->flags & IF_PREMULTIPLYALPHA))
|
||||
return false;
|
||||
// return false;
|
||||
|
||||
encoding = PTI_S3RGBA5;
|
||||
pad = 8;
|
||||
divsize = 4;
|
||||
|
@ -2525,8 +2528,8 @@ static qboolean Image_ReadDDSFile(texid_t tex, unsigned int flags, char *fname,
|
|||
}
|
||||
else if (*(int*)&fmtheader.ddpfPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('5'<<24)))
|
||||
{
|
||||
if (tex->flags & IF_PREMULTIPLYALPHA)
|
||||
return false;
|
||||
// if (tex->flags & IF_PREMULTIPLYALPHA)
|
||||
// return false;
|
||||
|
||||
encoding = PTI_S3RGBA5;
|
||||
pad = 8;
|
||||
|
@ -4410,8 +4413,7 @@ qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname,
|
|||
return false;
|
||||
}
|
||||
|
||||
//loads from a single mip. takes ownership of the data.
|
||||
static qboolean Image_LoadCubemapTexture(texid_t tex, char *nicename)
|
||||
struct pendingtextureinfo *Image_LoadCubemapTextureData(const char *nicename, char *subpath, unsigned int texflags)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
|
@ -4446,6 +4448,8 @@ static qboolean Image_LoadCubemapTexture(texid_t tex, char *nicename)
|
|||
size_t filesize;
|
||||
int width, height;
|
||||
qboolean hasalpha;
|
||||
char *nextprefix, *prefixend;
|
||||
size_t prefixlen;
|
||||
mips = Z_Malloc(sizeof(*mips));
|
||||
mips->type = PTI_CUBEMAP;
|
||||
mips->mipcount = 6;
|
||||
|
@ -4454,14 +4458,24 @@ static qboolean Image_LoadCubemapTexture(texid_t tex, char *nicename)
|
|||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
for (e = (tex->flags & IF_EXACTEXTENSION)?tex_extensions_count-1:0; e < tex_extensions_count; e++)
|
||||
prefixlen = 0;
|
||||
nextprefix = subpath;
|
||||
for(;;)
|
||||
{
|
||||
for (e = (texflags & IF_EXACTEXTENSION)?tex_extensions_count-1:0; e < tex_extensions_count; e++)
|
||||
{
|
||||
//try and open one
|
||||
qbyte *buf = NULL, *data;
|
||||
filesize = 0;
|
||||
|
||||
for (j = 0; j < sizeof(cmscheme)/sizeof(cmscheme[0])/6; j++)
|
||||
{
|
||||
Q_snprintfz(fname, sizeof(fname), "%s%s%s", nicename, cmscheme[i + 6*j].suffix, tex_extensions[e].name);
|
||||
Q_snprintfz(fname+prefixlen, sizeof(fname)-prefixlen, "%s_%s%s", nicename, cmscheme[i + 6*j].suffix, tex_extensions[e].name);
|
||||
buf = COM_LoadFile(fname, 5, &filesize);
|
||||
if (buf)
|
||||
break;
|
||||
|
||||
Q_snprintfz(fname+prefixlen, sizeof(fname)-prefixlen, "%s%s%s", nicename, cmscheme[i + 6*j].suffix, tex_extensions[e].name);
|
||||
buf = COM_LoadFile(fname, 5, &filesize);
|
||||
if (buf)
|
||||
break;
|
||||
|
@ -4473,7 +4487,9 @@ static qboolean Image_LoadCubemapTexture(texid_t tex, char *nicename)
|
|||
if ((data = Read32BitImageFile(buf, filesize, &width, &height, &hasalpha, fname)))
|
||||
{
|
||||
extern cvar_t vid_hardwaregamma;
|
||||
if (!(tex->flags&IF_NOGAMMA) && !vid_hardwaregamma.value)
|
||||
if (width == height && (!i || width == mips->mip[0].width)) //cubemaps must be square and all the same size (npot is fine though)
|
||||
{ //(skies have a fallback for invalid sizes, but it'll run a bit slower)
|
||||
if (!(texflags&IF_NOGAMMA) && !vid_hardwaregamma.value)
|
||||
BoostGamma(data, width, height);
|
||||
mips->mip[i].data = R_FlipImage32(data, &width, &height, cmscheme[i + 6*j].flipx, cmscheme[i + 6*j].flipy, cmscheme[i + 6*j].flipd);
|
||||
mips->mip[i].datasize = width*height*4;
|
||||
|
@ -4481,24 +4497,40 @@ static qboolean Image_LoadCubemapTexture(texid_t tex, char *nicename)
|
|||
mips->mip[i].height = height;
|
||||
mips->mip[i].needfree = true;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
tex->width = width;
|
||||
tex->height = height;
|
||||
BZ_Free(buf);
|
||||
goto nextface;
|
||||
}
|
||||
BZ_Free(data);
|
||||
}
|
||||
BZ_Free(buf);
|
||||
break;
|
||||
}
|
||||
BZ_Free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tex->flags & IF_NOWORKER)
|
||||
Image_LoadTextureMips(tex, mips, 0, 0);
|
||||
else
|
||||
COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0);
|
||||
return true;
|
||||
//get ready for the next prefix...
|
||||
if (!nextprefix || !*nextprefix)
|
||||
break; //no more...
|
||||
prefixend = strchr(nextprefix, ':');
|
||||
if (!prefixend)
|
||||
prefixend = nextprefix+strlen(nextprefix);
|
||||
|
||||
prefixlen = prefixend-nextprefix;
|
||||
if (prefixlen >= sizeof(fname)-2)
|
||||
prefixlen = sizeof(fname)-2;
|
||||
memcpy(fname, nextprefix, prefixlen);
|
||||
fname[prefixlen++] = '/';
|
||||
|
||||
if (*prefixend)
|
||||
prefixend++;
|
||||
nextprefix = prefixend;
|
||||
}
|
||||
|
||||
while(i>0)
|
||||
BZ_Free(mips->mip[i--].data);
|
||||
Z_Free(mips);
|
||||
return NULL;
|
||||
nextface:;
|
||||
}
|
||||
return mips;
|
||||
}
|
||||
|
||||
static qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *bestname, size_t bestnamesize, unsigned int *bestflags)
|
||||
|
@ -4740,6 +4772,9 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t
|
|||
//the exception is single-file dds cubemaps, but we don't support those.
|
||||
for(altname = tex->ident;altname;altname = nextalt)
|
||||
{
|
||||
char *prefixes[] = {"textures/", "", NULL};
|
||||
struct pendingtextureinfo *mips;
|
||||
|
||||
nextalt = strchr(altname, ':');
|
||||
if (nextalt)
|
||||
{
|
||||
|
@ -4751,14 +4786,23 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t
|
|||
altname = fname;
|
||||
}
|
||||
|
||||
if (!Image_LoadCubemapTexture(tex, altname))
|
||||
mips = Image_LoadCubemapTextureData(altname, tex->subpath, tex->flags);
|
||||
if (mips)
|
||||
{
|
||||
tex->width = mips->mip[0].width;
|
||||
tex->height = mips->mip[0].height;
|
||||
|
||||
if (tex->flags & IF_NOWORKER)
|
||||
Image_LoadTextureMips(tex, mips, 0, 0);
|
||||
else
|
||||
COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (tex->flags & IF_NOWORKER)
|
||||
Image_LoadTexture_Failed(tex, NULL, 0, 0);
|
||||
else
|
||||
COM_AddWork(WG_MAIN, Image_LoadTexture_Failed, tex, NULL, 0, 0);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -758,6 +758,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame
|
|||
mouse_y *= sensitivity.value*in_sensitivityscale;
|
||||
}
|
||||
|
||||
/*
|
||||
#ifdef QUAKESTATS
|
||||
if (cl.playerview[pnum].statsf[STAT_VIEWZOOM])
|
||||
{
|
||||
|
@ -765,6 +766,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame
|
|||
mouse_y *= cl.playerview[pnum].statsf[STAT_VIEWZOOM]/STAT_VIEWZOOM_SCALE;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
if (!movements)
|
||||
{
|
||||
|
|
|
@ -3211,6 +3211,10 @@ static void P_ImportEffectInfo(char *config, char *line)
|
|||
Con_DPrintf("Particle effect token %s not supported\n", arg[0]);
|
||||
else if (!strcmp(arg[0], "stainless") && args == 2)
|
||||
Con_DPrintf("Particle effect token %s not supported\n", arg[0]);
|
||||
else if (!strcmp(arg[0], "relativeoriginoffset") && args == 4)
|
||||
Con_DPrintf("Particle effect token %s not supported\n", arg[0]);
|
||||
else if (!strcmp(arg[0], "relativevelocityoffset") && args == 4)
|
||||
Con_DPrintf("Particle effect token %s not supported\n", arg[0]);
|
||||
#endif
|
||||
else if (!strcmp(arg[0], "rotate") && args == 5)
|
||||
{
|
||||
|
|
|
@ -43,6 +43,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "pr_common.h"
|
||||
|
||||
extern usercmd_t cl_pendingcmd[MAX_SPLITS];
|
||||
|
||||
|
||||
#ifndef TEXTEDITOR
|
||||
//client only builds don't have a qc debugger
|
||||
#define QCEditor NULL
|
||||
|
@ -68,7 +71,11 @@ world_t csqc_world;
|
|||
int csqc_playerseat; //can be negative.
|
||||
static playerview_t *csqc_playerview;
|
||||
qboolean csqc_dp_lastwas3d; //to emulate DP correctly, we need to track whether drawpic/drawfill or clearscene was called last. blame 515.
|
||||
#ifdef NOLEGACY
|
||||
#define csqc_isdarkplaces false //hopefully this will allow a smart enough compiler to optimise it out cleanly
|
||||
#else
|
||||
static qboolean csqc_isdarkplaces;
|
||||
#endif
|
||||
static qboolean csqc_singlecheats; /*single player or cheats active, allowing custom addons*/
|
||||
static qboolean csqc_mayread; //csqc is allowed to ReadByte();
|
||||
static qboolean csqc_worldchanged; //make sure any caches are rebuilt properly before the next renderscene
|
||||
|
@ -98,6 +105,19 @@ extern sfx_t *cl_sfx_ric2;
|
|||
extern sfx_t *cl_sfx_ric3;
|
||||
extern sfx_t *cl_sfx_r_exp3;
|
||||
|
||||
#define ENDLIST
|
||||
#ifdef NOLEGACY
|
||||
#define legacycsqcglobals
|
||||
#else
|
||||
#define legacycsqcglobals \
|
||||
globalstring(trace_dphittexturename, "trace_dphittexturename"); /*for dp compat*/ \
|
||||
globalfloat(trace_dpstartcontents, "trace_dpstartcontents"); /*for dp compat*/ \
|
||||
globalfloat(trace_dphitcontents, "trace_dphitcontents"); /*for dp compat*/ \
|
||||
globalfloat(trace_dphitq3surfaceflags, "trace_dphitq3surfaceflags"); /*for dp compat*/ \
|
||||
globalfloat(trace_surfaceflagsf, "trace_surfaceflagsf"); /*float written by traceline, for mods that lack ints*/ \
|
||||
globalfloat(trace_endcontentsf, "trace_endcontentsf"); /*float written by traceline EXT_CSQC_1, for mods that lack ints*/ \
|
||||
ENDLIST
|
||||
#endif
|
||||
|
||||
//If I do it like this, I'll never forget to register something...
|
||||
#define csqcglobals \
|
||||
|
@ -119,6 +139,7 @@ extern sfx_t *cl_sfx_r_exp3;
|
|||
globalfunction(console_link, "CSQC_ConsoleLink"); \
|
||||
globalfunction(gamecommand, "GameCommand"); /*DP extension*/\
|
||||
\
|
||||
globalfunction(ent_spawn, "CSQC_Ent_Spawn"); \
|
||||
globalfunction(ent_update, "CSQC_Ent_Update"); \
|
||||
globalfunction(ent_remove, "CSQC_Ent_Remove"); \
|
||||
\
|
||||
|
@ -158,16 +179,15 @@ extern sfx_t *cl_sfx_r_exp3;
|
|||
globalvector(trace_plane_normal, "trace_plane_normal"); /*vector written by traceline*/ \
|
||||
globalfloat(trace_plane_dist, "trace_plane_dist"); /*float written by traceline*/ \
|
||||
globalentity(trace_ent, "trace_ent"); /*entity written by traceline*/ \
|
||||
globalfloat(trace_surfaceflagsf, "trace_surfaceflagsf"); /*float written by traceline*/ \
|
||||
globalint(trace_surfaceflagsi, "trace_surfaceflagsi"); /*int written by traceline*/ \
|
||||
globalstring(trace_surfacename, "trace_surfacename"); /*string written by traceline*/ \
|
||||
globalfloat(trace_endcontentsf, "trace_endcontentsf"); /*float written by traceline EXT_CSQC_1*/ \
|
||||
globalint(trace_endcontentsi, "trace_endcontentsi"); /*int written by traceline EXT_CSQC_1*/ \
|
||||
globalint(trace_brush_id, "trace_brush_id"); /*int written by traceline*/ \
|
||||
globalint(trace_brush_faceid, "trace_brush_faceid"); /*int written by traceline*/ \
|
||||
globalint(trace_surface_id, "trace_surface_id"); /*int written by traceline*/ \
|
||||
globalint(trace_bone_id, "trace_bone_id"); /*int written by traceline*/ \
|
||||
globalint(trace_triangle_id, "trace_triangle_id"); /*int written by traceline*/ \
|
||||
legacycsqcglobals \
|
||||
\
|
||||
globalfloat(clientcommandframe, "clientcommandframe"); /*float the next frame that will be sent*/ \
|
||||
globalfloat(servercommandframe, "servercommandframe"); /*float the most recent frame received from the server*/ \
|
||||
|
@ -183,6 +203,7 @@ extern sfx_t *cl_sfx_r_exp3;
|
|||
globalvector(pmove_maxs, "pmove_maxs"); /*deprecated. read/written by runplayerphysics*/ \
|
||||
globalfloat(pmove_jump_held, "pmove_jump_held"); /*deprecated. read/written by runplayerphysics*/ \
|
||||
globalfloat(pmove_waterjumptime, "pmove_waterjumptime"); /*deprecated. read/written by runplayerphysics*/ \
|
||||
globalfloat(pmove_onground, "pmove_onground"); /*deprecated. read/written by runplayerphysics*/ \
|
||||
\
|
||||
globalfloat(input_timelength, "input_timelength"); /*float filled by getinputstate, read by runplayerphysics*/ \
|
||||
globalvector(input_angles, "input_angles"); /*vector filled by getinputstate, read by runplayerphysics*/ \
|
||||
|
@ -203,7 +224,7 @@ extern sfx_t *cl_sfx_r_exp3;
|
|||
globalfloat(autocvar_vid_conwidth, "autocvar_vid_conwidth"); /*float hackfix for dp mods*/ \
|
||||
globalfloat(autocvar_vid_conheight, "autocvar_vid_conheight"); /*float hackfix for dp mods*/ \
|
||||
globalfloat(cycle_wrapped, "cycle_wrapped"); \
|
||||
|
||||
ENDLIST
|
||||
|
||||
typedef struct {
|
||||
#define globalfloat(name,qcname) float *name
|
||||
|
@ -265,30 +286,33 @@ static void CSQC_ChangeLocalPlayer(int seat)
|
|||
}
|
||||
if ((unsigned int)seat < MAX_SPLITS)
|
||||
{
|
||||
extern usercmd_t independantphysics[MAX_SPLITS];
|
||||
int i;
|
||||
usercmd_t *cmd = &independantphysics[seat];
|
||||
usercmd_t tmp;
|
||||
for (i=0 ; i<3 ; i++)
|
||||
cmd->angles[i] = ((int)(csqc_playerview->viewangles[i]*65536.0/360)&65535);
|
||||
if (!cmd->msec)
|
||||
CL_BaseMove (cmd, seat, 0, 72);
|
||||
tmp = *cmd;
|
||||
cmd = &tmp;
|
||||
cmd->msec = (realtime - cl.outframes[(cl.movesequence-1)&UPDATE_MASK].senttime)*1000;
|
||||
// int i;
|
||||
usercmd_t *cmd = &cl_pendingcmd[seat];
|
||||
// usercmd_t tmp;
|
||||
// for (i=0 ; i<3 ; i++)
|
||||
// cmd->angles[i] = ((int)(csqc_playerview->viewangles[i]*65536.0/360)&65535);
|
||||
// if (!cmd->msec)
|
||||
// CL_BaseMove (cmd, seat, cmd->msec, newtime);
|
||||
// tmp = *cmd;
|
||||
// cmd = &tmp;
|
||||
// cmd->msec = (realtime - cl.outframes[(cl.movesequence-1)&UPDATE_MASK].senttime)*1000;
|
||||
cs_set_input_state(cmd);
|
||||
|
||||
if (csqcg.pmove_org)
|
||||
{
|
||||
csqcg.pmove_org[0] = csqc_playerview->simorg[0];
|
||||
csqcg.pmove_org[1] = csqc_playerview->simorg[1];
|
||||
csqcg.pmove_org[2] = csqc_playerview->simorg[2];
|
||||
}
|
||||
VectorCopy(csqc_playerview->simorg, csqcg.pmove_org);
|
||||
if (csqc_isdarkplaces)
|
||||
{ //dp mods tend to require these to be totally unlerped
|
||||
if (csqcg.pmove_vel)
|
||||
VectorCopy(cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[csqc_playerview->playernum].velocity, csqcg.pmove_vel);
|
||||
if (csqcg.pmove_onground)
|
||||
*csqcg.pmove_onground = cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[csqc_playerview->playernum].onground;
|
||||
}
|
||||
else
|
||||
{
|
||||
csqcg.pmove_vel[0] = csqc_playerview->simvel[0];
|
||||
csqcg.pmove_vel[1] = csqc_playerview->simvel[1];
|
||||
csqcg.pmove_vel[2] = csqc_playerview->simvel[2];
|
||||
if (csqcg.pmove_vel)
|
||||
VectorCopy(csqc_playerview->simvel, csqcg.pmove_vel);
|
||||
if (csqcg.pmove_onground)
|
||||
*csqcg.pmove_onground = csqc_playerview->onground;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -320,6 +344,15 @@ static void CSQC_FindGlobals(qboolean nofuncs)
|
|||
#define ensurevector(name) if (!csqcg.name) csqcg.name = junk._vector;
|
||||
#define ensureentity(name) if (!csqcg.name) csqcg.name = &junk.edict;
|
||||
|
||||
#ifdef NOLEGACY
|
||||
{
|
||||
etype_t etype = ev_void;
|
||||
if (!csqcg.trace_surfaceflagsi)
|
||||
csqcg.trace_surfaceflagsi = PR_FindGlobal(csqcprogs, "trace_surfaceflags", 0, &etype);
|
||||
if (!csqcg.trace_endcontentsi)
|
||||
csqcg.trace_endcontentsi = PR_FindGlobal(csqcprogs, "trace_endcontents", 0, &etype);
|
||||
}
|
||||
#else
|
||||
if (!csqcg.trace_surfaceflagsf && !csqcg.trace_surfaceflagsi)
|
||||
{
|
||||
etype_t etype = ev_void;
|
||||
|
@ -338,6 +371,9 @@ static void CSQC_FindGlobals(qboolean nofuncs)
|
|||
else if (etype == ev_integer)
|
||||
csqcg.trace_endcontentsi = &v->_int;
|
||||
}
|
||||
ensurefloat(trace_surfaceflagsf);
|
||||
ensurefloat(trace_endcontentsf);
|
||||
#endif
|
||||
|
||||
ensurefloat(trace_allsolid);
|
||||
ensurefloat(trace_startsolid);
|
||||
|
@ -347,9 +383,7 @@ static void CSQC_FindGlobals(qboolean nofuncs)
|
|||
ensurevector(trace_endpos);
|
||||
ensurevector(trace_plane_normal);
|
||||
ensurefloat(trace_plane_dist);
|
||||
ensurefloat(trace_surfaceflagsf);
|
||||
ensureint(trace_surfaceflagsi);
|
||||
ensurefloat(trace_endcontentsf);
|
||||
ensureint(trace_endcontentsi);
|
||||
ensureint(trace_brush_id);
|
||||
ensureint(trace_brush_faceid);
|
||||
|
@ -456,7 +490,12 @@ typedef struct csqcedict_s
|
|||
};
|
||||
#endif
|
||||
/*the above is shared with qclib*/
|
||||
#ifdef USEAREAGRID
|
||||
areagridlink_t gridareas[AREAGRIDPERENT]; //on overflow, use the inefficient overflow list.
|
||||
size_t gridareasequence; //used to avoid iterrating the same ent twice.
|
||||
#else
|
||||
link_t area;
|
||||
#endif
|
||||
pvscache_t pvsinfo;
|
||||
int lastruntime;
|
||||
int solidsize;
|
||||
|
@ -866,7 +905,7 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
|
|||
out->topcolour = cl.players[ival-1].ttopcolor;
|
||||
out->bottomcolour = cl.players[ival-1].tbottomcolor;
|
||||
}
|
||||
else if (ival >= 1024)
|
||||
else if (ival /*>= 1024*/)
|
||||
{
|
||||
//DP COLORMAP extension
|
||||
out->topcolour = (ival>>4) & 0x0f;
|
||||
|
@ -879,28 +918,23 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
|
|||
}
|
||||
|
||||
if (!in->xv->colormod[0] && !in->xv->colormod[1] && !in->xv->colormod[2])
|
||||
{
|
||||
out->shaderRGBAf[0] = 1;
|
||||
out->shaderRGBAf[1] = 1;
|
||||
out->shaderRGBAf[2] = 1;
|
||||
}
|
||||
VectorSet(out->shaderRGBAf, 1, 1, 1);
|
||||
else
|
||||
{
|
||||
out->flags |= RF_FORCECOLOURMOD;
|
||||
out->shaderRGBAf[0] = in->xv->colormod[0];
|
||||
out->shaderRGBAf[1] = in->xv->colormod[1];
|
||||
out->shaderRGBAf[2] = in->xv->colormod[2];
|
||||
VectorCopy(in->xv->colormod, out->shaderRGBAf);
|
||||
}
|
||||
if (!in->xv->alpha || in->xv->alpha == 1)
|
||||
{
|
||||
out->shaderRGBAf[3] = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
out->flags |= RF_TRANSLUCENT;
|
||||
out->shaderRGBAf[3] = in->xv->alpha;
|
||||
}
|
||||
|
||||
if (!in->xv->glowmod[0] && !in->xv->glowmod[1] && !in->xv->glowmod[2])
|
||||
VectorSet(out->glowmod, 1, 1, 1);
|
||||
else
|
||||
VectorCopy(in->xv->glowmod, out->glowmod);
|
||||
|
||||
#ifdef HEXEN2
|
||||
|
@ -1217,6 +1251,7 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva
|
|||
int maxe;
|
||||
|
||||
int oldself = *csqcg.self;
|
||||
RSpeedMark();
|
||||
|
||||
if (cl.worldmodel)
|
||||
{
|
||||
|
@ -1307,6 +1342,8 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva
|
|||
CL_UpdateTEnts ();
|
||||
}
|
||||
}
|
||||
|
||||
RSpeedEnd(RSPEED_LINKENTITIES);
|
||||
}
|
||||
|
||||
//enum {vb_vertexcoord, vb_texcoord, vb_rgba, vb_normal, vb_sdir, vb_tdir, vb_indexes, vb_rgb, vb_alpha};
|
||||
|
@ -1385,8 +1422,10 @@ static void CSQC_PolyFlush(void)
|
|||
// #306 void(string texturename) R_BeginPolygon (EXT_CSQC_???)
|
||||
void QCBUILTIN PF_R_PolygonBegin(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
shader_t *shader;
|
||||
const char *shadername = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
int qcflags = (prinst->callargc > 1)?G_FLOAT(OFS_PARM1):0;
|
||||
shader_t *shader;
|
||||
extern shader_t *shader_draw_fill_trans;
|
||||
int beflags;
|
||||
qboolean twod;
|
||||
|
||||
|
@ -1407,10 +1446,12 @@ void QCBUILTIN PF_R_PolygonBegin(pubprogfuncs_t *prinst, struct globalvars_s *pr
|
|||
if (csqc_isdarkplaces || (qcflags & DRAWFLAG_TWOSIDED))
|
||||
beflags |= BEF_FORCETWOSIDED;
|
||||
|
||||
if (twod)
|
||||
shader = R_RegisterPic(PR_GetStringOfs(prinst, OFS_PARM0), NULL);
|
||||
if (!*shadername)
|
||||
shader = shader_draw_fill_trans; //dp compat...
|
||||
else if (twod)
|
||||
shader = R_RegisterPic(shadername, NULL);
|
||||
else
|
||||
shader = R_RegisterSkin(PR_GetStringOfs(prinst, OFS_PARM0), NULL);
|
||||
shader = R_RegisterSkin(shadername, NULL);
|
||||
|
||||
if (R2D_Flush && (R2D_Flush != CSQC_PolyFlush || csqc_poly_shader != shader || csqc_poly_flags != beflags || csqc_poly_2d != twod))
|
||||
R2D_Flush();
|
||||
|
@ -2361,11 +2402,9 @@ static void cs_settracevars(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
|||
VectorCopy (tr->endpos, csqcg.trace_endpos);
|
||||
VectorCopy (tr->plane.normal, csqcg.trace_plane_normal);
|
||||
*csqcg.trace_plane_dist = tr->plane.dist;
|
||||
*csqcg.trace_surfaceflagsf = tr->surface?tr->surface->flags:0;
|
||||
*csqcg.trace_surfaceflagsi = tr->surface?tr->surface->flags:0;
|
||||
if (csqcg.trace_surfacename)
|
||||
prinst->SetStringField(prinst, NULL, csqcg.trace_surfacename, tr->surface?tr->surface->name:NULL, true);
|
||||
*csqcg.trace_endcontentsf = tr->contents;
|
||||
*csqcg.trace_endcontentsi = tr->contents;
|
||||
*csqcg.trace_brush_id = tr->brush_id;
|
||||
*csqcg.trace_brush_faceid = tr->brush_face;
|
||||
|
@ -2376,6 +2415,20 @@ static void cs_settracevars(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
|||
*csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)tr->ent);
|
||||
else
|
||||
*csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)csqc_world.edicts);
|
||||
|
||||
#ifndef NOLEGACY
|
||||
*csqcg.trace_endcontentsf = tr->contents;
|
||||
*csqcg.trace_surfaceflagsf = tr->surface?tr->surface->flags:0;
|
||||
|
||||
if (csqcg.trace_dphittexturename)
|
||||
prinst->SetStringField(prinst, NULL, csqcg.trace_dphittexturename, tr->surface?tr->surface->name:NULL, true);
|
||||
if (csqcg.trace_dpstartcontents)
|
||||
*csqcg.trace_dpstartcontents = FTEToDPContents(0); //fixme, maybe
|
||||
if (csqcg.trace_dphitcontents)
|
||||
*csqcg.trace_dphitcontents = FTEToDPContents(tr->contents);
|
||||
if (csqcg.trace_dphitq3surfaceflags)
|
||||
*csqcg.trace_dphitq3surfaceflags = tr->surface?tr->surface->flags:0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void QCBUILTIN PF_cs_traceline(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
|
@ -3091,7 +3144,7 @@ static void cs_set_input_state (usercmd_t *cmd)
|
|||
if (csqcg.input_weapon)
|
||||
*csqcg.input_weapon = cmd->weapon;
|
||||
if (csqcg.input_servertime)
|
||||
*csqcg.input_servertime = cmd->servertime/1000.0f;
|
||||
*csqcg.input_servertime = cmd->fservertime;
|
||||
if (csqcg.input_clienttime)
|
||||
*csqcg.input_clienttime = cmd->fclienttime/1000.0f;
|
||||
|
||||
|
@ -3134,7 +3187,7 @@ static void cs_get_input_state (usercmd_t *cmd)
|
|||
if (csqcg.input_weapon)
|
||||
cmd->weapon = *csqcg.input_weapon;
|
||||
if (csqcg.input_servertime)
|
||||
cmd->servertime = *csqcg.input_servertime*1000;
|
||||
cmd->fservertime = *csqcg.input_servertime;
|
||||
|
||||
if (csqcg.input_cursor_screen)
|
||||
Vector2Copy(csqcg.input_cursor_screen, cmd->cursor_screen);
|
||||
|
@ -3149,8 +3202,8 @@ static void cs_get_input_state (usercmd_t *cmd)
|
|||
//get the input commands, and stuff them into some globals.
|
||||
static void QCBUILTIN PF_cs_getinputstate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
usercmd_t *cmd, tmp;
|
||||
extern usercmd_t independantphysics[MAX_SPLITS];
|
||||
usercmd_t *cmd;
|
||||
extern usercmd_t cl_pendingcmd[MAX_SPLITS];
|
||||
int f = G_FLOAT(OFS_PARM0);
|
||||
int seat = ((prinst->callargc>1)?G_FLOAT(OFS_PARM1):csqc_playerseat);
|
||||
|
||||
|
@ -3170,9 +3223,10 @@ static void QCBUILTIN PF_cs_getinputstate (pubprogfuncs_t *prinst, struct global
|
|||
/*outgoing_sequence says how many packets have actually been sent, but there's an extra pending packet which has not been sent yet - be warned though, its data will change in the coming frames*/
|
||||
if (f == cl.movesequence)
|
||||
{
|
||||
int i;
|
||||
cmd = &independantphysics[seat];
|
||||
|
||||
// int i;
|
||||
// usercmd_t tmp;
|
||||
cmd = &cl_pendingcmd[seat];
|
||||
/*
|
||||
tmp = *cmd;
|
||||
cmd = &tmp;
|
||||
for (i=0 ; i<3 ; i++)
|
||||
|
@ -3180,9 +3234,13 @@ static void QCBUILTIN PF_cs_getinputstate (pubprogfuncs_t *prinst, struct global
|
|||
if (!cmd->msec)
|
||||
{
|
||||
// *cmd = cl.outframes[(f-1)&UPDATE_MASK].cmd[seat];
|
||||
CL_BaseMove (cmd, seat, 0, 72);
|
||||
CL_BaseMove (cmd, seat, cmd->msec, newtime);
|
||||
}
|
||||
// if (cl.predservertimes)
|
||||
// cmd->msec = (cl.time - cl.outframes[(f-1)&UPDATE_MASK].cmd[seat].fservertime)*1000;
|
||||
// else
|
||||
cmd->msec = (realtime - cl.outframes[(f-1)&UPDATE_MASK].senttime)*1000;
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3203,7 +3261,7 @@ static void QCBUILTIN PF_cs_getinputstate (pubprogfuncs_t *prinst, struct global
|
|||
//not intended to affect client state at all
|
||||
static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
unsigned int msecs;
|
||||
float msecs;
|
||||
float oldtime = *csqcg.simtime;
|
||||
|
||||
csqcedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
|
||||
|
@ -3228,7 +3286,7 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
|
|||
pmove.jump_msec = 0;//(cls.z_ext & Z_EXT_PM_TYPE) ? 0 : from->jump_msec;
|
||||
|
||||
//set up the movement command
|
||||
msecs = *csqcg.input_timelength*1000 + 0.5f;
|
||||
msecs = *csqcg.input_timelength*1000;
|
||||
//precision inaccuracies. :(
|
||||
pmove.cmd.angles[0] = ANGLE2SHORT(csqcg.input_angles[0]);
|
||||
pmove.cmd.angles[1] = ANGLE2SHORT(csqcg.input_angles[1]);
|
||||
|
@ -3270,7 +3328,7 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
|
|||
|
||||
CL_SetSolidEntities();
|
||||
|
||||
while(msecs) //break up longer commands
|
||||
while(msecs > 0) //break up longer commands
|
||||
{
|
||||
pmove.cmd.msec = msecs;
|
||||
if (pmove.cmd.msec > 50)
|
||||
|
@ -3587,8 +3645,17 @@ static void QCBUILTIN PF_cs_serverkey (pubprogfuncs_t *prinst, struct globalvars
|
|||
else
|
||||
G_INT(OFS_RETURN) = 0;
|
||||
}
|
||||
static void QCBUILTIN PF_cs_serverkeyfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
const char *keyname = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
const char *ret = PF_cs_serverkey_internal(keyname);
|
||||
if (*ret)
|
||||
G_FLOAT(OFS_RETURN) = strtod(ret, NULL);
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = (prinst->callargc >= 2)?G_FLOAT(OFS_PARM1):0;
|
||||
}
|
||||
//string(float pnum, string keyname)
|
||||
static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
static void QCBUILTIN PF_cs_getplayerkeystring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
int pnum = G_FLOAT(OFS_PARM0);
|
||||
const char *keyname = PR_GetStringOfs(prinst, OFS_PARM1);
|
||||
|
@ -3612,6 +3679,30 @@ static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalv
|
|||
else
|
||||
G_INT(OFS_RETURN) = 0;
|
||||
}
|
||||
static void QCBUILTIN PF_cs_getplayerkeyfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
int pnum = G_FLOAT(OFS_PARM0);
|
||||
const char *keyname = PR_GetStringOfs(prinst, OFS_PARM1);
|
||||
const char *ret;
|
||||
if (pnum < 0)
|
||||
{
|
||||
if (csqc_resortfrags)
|
||||
{
|
||||
Sbar_SortFrags(true, false);
|
||||
csqc_resortfrags = false;
|
||||
}
|
||||
if (pnum >= -scoreboardlines)
|
||||
{//sort by
|
||||
pnum = fragsort[-(pnum+1)];
|
||||
}
|
||||
}
|
||||
|
||||
ret = PF_cs_getplayerkey_internal(pnum, keyname);
|
||||
if (*ret)
|
||||
G_FLOAT(OFS_RETURN) = strtod(ret, NULL);
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = (prinst->callargc >= 3)?G_FLOAT(OFS_PARM2):0;
|
||||
}
|
||||
|
||||
static void QCBUILTIN PF_cs_infokey (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
|
@ -4873,6 +4964,7 @@ qboolean CSQC_DeltaUpdate(entity_state_t *src)
|
|||
else
|
||||
{
|
||||
ent = (csqcedict_t *)ED_Alloc(csqcprogs, false, 0);
|
||||
if (!csqc_isdarkplaces)
|
||||
ent->xv->drawmask = MASK_DELTA;
|
||||
}
|
||||
|
||||
|
@ -6000,7 +6092,8 @@ static struct {
|
|||
|
||||
{"runstandardplayerphysics",PF_cs_runplayerphysics, 347}, // #347 void() runstandardplayerphysics (EXT_CSQC)
|
||||
|
||||
{"getplayerkeyvalue", PF_cs_getplayerkey, 348}, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
|
||||
{"getplayerkeyvalue", PF_cs_getplayerkeystring, 348}, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
|
||||
{"getplayerkeyfloat", PF_cs_getplayerkeyfloat, 0}, // #348 string(float playernum, string keyname) getplayerkeyvalue
|
||||
|
||||
{"isdemo", PF_cl_playingdemo, 349}, // #349 float() isdemo (EXT_CSQC)
|
||||
//350
|
||||
|
@ -6012,6 +6105,7 @@ static struct {
|
|||
{"wasfreed", PF_WasFreed, 353}, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
|
||||
|
||||
{"serverkey", PF_cs_serverkey, 354}, // #354 string(string key) serverkey;
|
||||
{"serverkeyfloat", PF_cs_serverkeyfloat, 0}, // #0 float(string key) serverkeyfloat;
|
||||
{"getentitytoken", PF_cs_getentitytoken, 355}, // #355 string() getentitytoken;
|
||||
{"findfont", PF_CL_findfont, 356},
|
||||
{"loadfont", PF_CL_loadfont, 357},
|
||||
|
@ -6521,6 +6615,8 @@ static model_t *QDECL CSQC_World_ModelForIndex(world_t *w, int modelindex)
|
|||
model_t *mod = CSQC_GetModelForIndex(modelindex);
|
||||
if (mod && mod->loadstate != MLS_LOADED)
|
||||
{
|
||||
if (mod->loadstate == MLS_NOTLOADED)
|
||||
Mod_LoadModel(mod, MLV_SILENT);
|
||||
if (mod->loadstate == MLS_LOADING)
|
||||
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
|
||||
if (mod->loadstate != MLS_LOADED)
|
||||
|
@ -6831,6 +6927,7 @@ void ASMCALL CSQC_ThinkTimeOp(pubprogfuncs_t *progs, edict_t *ed, float var)
|
|||
|
||||
pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc)
|
||||
{
|
||||
#ifndef csqc_isdarkplaces
|
||||
if (!num)
|
||||
{
|
||||
if (crc == 22390)
|
||||
|
@ -6846,6 +6943,7 @@ pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc)
|
|||
Con_Printf(CON_WARNING "Running outdated or unknown csprogs.dat version\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6961,7 +7059,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
|
|||
csqcprogs = InitProgs(&csqcprogparms);
|
||||
csqc_world.progs = csqcprogs;
|
||||
csqc_world.usesolidcorpse = true;
|
||||
PR_Configure(csqcprogs, pr_csqc_memsize.ival, MAX_PROGS, pr_enable_profiling.ival);
|
||||
PR_Configure(csqcprogs, PR_ReadBytesString(pr_csqc_memsize.string), MAX_PROGS, pr_enable_profiling.ival);
|
||||
csqc_world.worldmodel = cl.worldmodel;
|
||||
csqc_world.Event_Touch = CSQC_Event_Touch;
|
||||
csqc_world.Event_Think = CSQC_Event_Think;
|
||||
|
@ -6978,7 +7076,9 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifndef csqc_isdarkplaces
|
||||
csqc_isdarkplaces = false;
|
||||
#endif
|
||||
if (csdatenabled || csqc_singlecheats || anycsqc)
|
||||
{
|
||||
csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat");
|
||||
|
@ -7057,6 +7157,8 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
|
|||
if (str)
|
||||
{
|
||||
char *s = Info_ValueForKey(cl.serverinfo, "map");
|
||||
if (!*s)
|
||||
s = cl.model_name[1];
|
||||
if (!*s)
|
||||
s = "unknown";
|
||||
*str = PR_NewString(csqcprogs, s);
|
||||
|
@ -7440,6 +7542,7 @@ qboolean CSQC_DrawView(void)
|
|||
int ticlimit = 10;
|
||||
float mintic = 0.01;
|
||||
double clframetime = host_frametime;
|
||||
RSpeedLocals();
|
||||
|
||||
csqc_resortfrags = true;
|
||||
csqctime = Sys_DoubleTime();
|
||||
|
@ -7457,6 +7560,7 @@ qboolean CSQC_DrawView(void)
|
|||
|
||||
csqc_dp_lastwas3d = false;
|
||||
|
||||
RSpeedRemark();
|
||||
if (csqc_isdarkplaces && *csqc_world.g.physics_mode == 1)
|
||||
{
|
||||
csqc_world.physicstime = cl.servertime;
|
||||
|
@ -7490,12 +7594,12 @@ qboolean CSQC_DrawView(void)
|
|||
csqc_world.physicstime += host_frametime;
|
||||
}
|
||||
}
|
||||
RSpeedEnd(RSPEED_CSQCPHYSICS);
|
||||
|
||||
RSpeedRemark();
|
||||
|
||||
host_frametime = clframetime;
|
||||
|
||||
//always revert to a usable default.
|
||||
CSQC_ChangeLocalPlayer(cl_forceseat.ival?(cl_forceseat.ival - 1) % cl.splitclients:0);
|
||||
|
||||
if (csqcg.frametime)
|
||||
{
|
||||
if (csqc_isdarkplaces)
|
||||
|
@ -7516,28 +7620,6 @@ qboolean CSQC_DrawView(void)
|
|||
if (csqcg.numclientseats)
|
||||
*csqcg.numclientseats = cl.splitclients;
|
||||
|
||||
DropPunchAngle (csqc_playerview);
|
||||
if (cl.worldmodel)
|
||||
Surf_LessenStains();
|
||||
|
||||
if (!cl.paused)
|
||||
{
|
||||
if (csqcg.clientcommandframe)
|
||||
*csqcg.clientcommandframe = cl.movesequence;
|
||||
if (csqcg.servercommandframe)
|
||||
*csqcg.servercommandframe = cl.ackedmovesequence;
|
||||
if (csqcg.gamespeed)
|
||||
*csqcg.gamespeed = cl.gamespeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (csqcg.clientcommandframe)
|
||||
*csqcg.clientcommandframe = cl.movesequence;
|
||||
if (csqcg.servercommandframe)
|
||||
*csqcg.servercommandframe = cl.ackedmovesequence;
|
||||
if (csqcg.gamespeed)
|
||||
*csqcg.gamespeed = 0;
|
||||
}
|
||||
if (csqcg.intermission)
|
||||
*csqcg.intermission = cl.intermissionmode;
|
||||
|
||||
|
@ -7551,7 +7633,17 @@ qboolean CSQC_DrawView(void)
|
|||
*csqcg.cltime = realtime;
|
||||
if (csqcg.simtime)
|
||||
*csqcg.simtime = cl.servertime;
|
||||
|
||||
if (csqcg.clientcommandframe)
|
||||
*csqcg.clientcommandframe = cl.movesequence;
|
||||
if (csqcg.servercommandframe)
|
||||
*csqcg.servercommandframe = cl.ackedmovesequence;
|
||||
if (csqcg.gamespeed)
|
||||
*csqcg.gamespeed = cl.gamespeed;
|
||||
if (cl.paused)
|
||||
{
|
||||
if (csqcg.gamespeed)
|
||||
*csqcg.gamespeed = 0;
|
||||
}
|
||||
if (cl.currentpackentities && cl.previouspackentities)
|
||||
{
|
||||
if (csqcg.netnewtime)
|
||||
|
@ -7562,25 +7654,32 @@ qboolean CSQC_DrawView(void)
|
|||
*csqcg.netdeltatime = cl.currentpackentities->servertime - cl.previouspackentities->servertime;
|
||||
}
|
||||
|
||||
//always revert to a usable default.
|
||||
CSQC_ChangeLocalPlayer(cl_forceseat.ival?(cl_forceseat.ival - 1) % cl.splitclients:0);
|
||||
DropPunchAngle (csqc_playerview); //FIXME: this seems like the wrong place for this.
|
||||
if (cl.worldmodel)
|
||||
Surf_LessenStains();
|
||||
|
||||
CSQC_RunThreads(); //wake up any qc threads
|
||||
|
||||
#ifndef NOLEGACY
|
||||
if (csqcg.autocvar_vid_conwidth)
|
||||
*csqcg.autocvar_vid_conwidth = vid.width;
|
||||
if (csqcg.autocvar_vid_conheight)
|
||||
*csqcg.autocvar_vid_conheight = vid.height;
|
||||
#endif
|
||||
|
||||
//EXT_CSQC_1
|
||||
{
|
||||
void *pr_globals = PR_globals(csqcprogs, PR_CURRENT);
|
||||
G_FLOAT(OFS_PARM0) = vid.width;
|
||||
G_FLOAT(OFS_PARM1) = vid.height;
|
||||
G_FLOAT(OFS_PARM2) = !Key_Dest_Has(kdm_emenu) && !r_refdef.eyeoffset[0] && !r_refdef.eyeoffset[1];
|
||||
}
|
||||
//end EXT_CSQC_1
|
||||
|
||||
if (csqcg.f_updateviewloading && cls.state && cls.state < ca_active)
|
||||
PR_ExecuteProgram(csqcprogs, csqcg.f_updateviewloading);
|
||||
else
|
||||
PR_ExecuteProgram(csqcprogs, csqcg.f_updateview);
|
||||
}
|
||||
|
||||
if (*r_refdef.rt_destcolour[0].texname)
|
||||
{
|
||||
|
@ -7590,6 +7689,8 @@ qboolean CSQC_DrawView(void)
|
|||
BE_RenderToTextureUpdate2d(true);
|
||||
}
|
||||
|
||||
RSpeedEnd(RSPEED_CSQCREDRAW);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -8111,10 +8212,13 @@ void CSQC_ParseEntities(void)
|
|||
if (csqcg.netdeltatime)
|
||||
*csqcg.netdeltatime = cl.gametime - cl.oldgametime;
|
||||
|
||||
if (!csqc_isdarkplaces)
|
||||
{
|
||||
if (csqcg.clientcommandframe)
|
||||
*csqcg.clientcommandframe = cl.movesequence;
|
||||
if (csqcg.servercommandframe)
|
||||
*csqcg.servercommandframe = cl.ackedmovesequence;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
@ -8174,10 +8278,21 @@ void CSQC_ParseEntities(void)
|
|||
|
||||
ent = csqcent[entnum];
|
||||
if (!ent)
|
||||
{
|
||||
if (csqcg.ent_spawn)
|
||||
{
|
||||
*csqcg.self = 0;
|
||||
G_FLOAT(OFS_PARM0) = entnum;
|
||||
PR_ExecuteProgram(csqcprogs, csqcg.ent_spawn);
|
||||
ent = csqcent[entnum] = (csqcedict_t*)PROG_TO_WEDICT(csqcprogs, *csqcg.self); //allow the mod to change the ent.
|
||||
}
|
||||
else
|
||||
{
|
||||
ent = (csqcedict_t*)ED_Alloc(csqcprogs, false, 0);
|
||||
csqcent[entnum] = ent;
|
||||
ent->xv->entnum = entnum;
|
||||
}
|
||||
|
||||
G_FLOAT(OFS_PARM0) = true;
|
||||
|
||||
if (cl_csqcdebug.ival)
|
||||
|
@ -8194,6 +8309,8 @@ void CSQC_ParseEntities(void)
|
|||
csqc_mayread = true;
|
||||
PR_ExecuteProgram(csqcprogs, csqcg.ent_update);
|
||||
csqc_mayread = false;
|
||||
if (csqcg.ent_spawn)
|
||||
csqcent[entnum] = (csqcedict_t*)PROG_TO_WEDICT(csqcprogs, *csqcg.self); //allow the mod to change the ent.
|
||||
|
||||
if (cl.csqcdebug)
|
||||
{
|
||||
|
|
|
@ -366,7 +366,19 @@ void CL_LoadFont_f(void)
|
|||
|
||||
while(sizenum < Cmd_Argc())
|
||||
{
|
||||
int sz = atoi(Cmd_Argv(sizenum++));
|
||||
const char *a = Cmd_Argv(sizenum++);
|
||||
int sz;
|
||||
if (!strcmp(a, "scale"))
|
||||
{
|
||||
sizenum++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(a, "voffset"))
|
||||
{
|
||||
sizenum++;
|
||||
continue;
|
||||
}
|
||||
sz = atoi(a);
|
||||
if (sz <= 0)
|
||||
sz = 8;
|
||||
|
||||
|
@ -388,7 +400,8 @@ void CL_LoadFont_f(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (dpcompat_console.ival)
|
||||
//FIXME: slotnum0==default is problematic.
|
||||
if (dpcompat_console.ival && (slotnum == 1 || (slotnum == 0 && !*gl_font.string)))
|
||||
Cvar_Set(&gl_font, facename);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -923,10 +923,9 @@ float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int
|
|||
if (normal)
|
||||
VectorCopy (trace.plane.normal, normal);
|
||||
VectorAdd (pe->origin, trace.endpos, impact);
|
||||
}
|
||||
|
||||
result = pe->info;
|
||||
}
|
||||
}
|
||||
if (trace.startsolid)
|
||||
{
|
||||
if (normal)
|
||||
|
|
|
@ -4446,25 +4446,25 @@ char *particle_set_q2part =
|
|||
"{ //FIXME\n"
|
||||
"assoc placeholder\n"
|
||||
"}\n"
|
||||
"/*\n"
|
||||
"r_part teq2_heatbeam_steam\n"
|
||||
"{\n"
|
||||
"count 20\n"
|
||||
"colorindex 0xe0 7\n"
|
||||
// magnitude 60
|
||||
"texture \"classicparticle\"\n"
|
||||
"tcoords 0 0 16 16 32\n"
|
||||
"scale 1\n"
|
||||
"alpha 1\n"
|
||||
"die 0.3 0.8\n"
|
||||
"randomvel 20 magnitude/3\n"
|
||||
"veladd magnitude\n"
|
||||
"orgadd magnitude/10\n"
|
||||
"spawnorg 4\n"
|
||||
"gravity -400\n"
|
||||
"scalefactor 0.8\n"
|
||||
"}\n"
|
||||
"*/\n"
|
||||
|
||||
//r_part teq2_heatbeam_steam
|
||||
//{
|
||||
// count 20
|
||||
// colorindex 0xe0 7
|
||||
//// magnitude 60
|
||||
// texture "classicparticle"
|
||||
// tcoords 0 0 16 16 32
|
||||
// scale 1
|
||||
// alpha 1
|
||||
// die 0.3 0.8
|
||||
// randomvel 20 magnitude/3
|
||||
// veladd magnitude
|
||||
// orgadd magnitude/10
|
||||
// spawnorg 4
|
||||
// gravity -400
|
||||
// scalefactor 0.8
|
||||
//}
|
||||
|
||||
|
||||
//this is apparently just a trail effect (palette index specified by netcode)
|
||||
"r_part teq2_forcewall\n"
|
||||
|
|
|
@ -3371,7 +3371,7 @@ int Surf_NewExternalLightmaps(int count, char *filepattern, qboolean deluxe)
|
|||
|
||||
lightmap[i]->modified = false;
|
||||
lightmap[i]->external = true;
|
||||
lightmap[i]->hasdeluxe = (deluxe && ((i - numlightmaps)&1));
|
||||
lightmap[i]->hasdeluxe = (deluxe && !((i - numlightmaps)&1));
|
||||
|
||||
Q_snprintfz(nname, sizeof(nname), filepattern, i - numlightmaps);
|
||||
|
||||
|
@ -3685,6 +3685,12 @@ void Surf_NewMap (void)
|
|||
r_viewcluster2 = -1;
|
||||
r_oldviewcluster2 = 0;
|
||||
|
||||
TRACE(("dbg: Surf_NewMap: clear particles\n"));
|
||||
P_ClearParticles ();
|
||||
CL_RegisterParticles();
|
||||
|
||||
Shader_DoReload();
|
||||
|
||||
if (cl.worldmodel)
|
||||
{
|
||||
if (cl.worldmodel->loadstate == MLS_LOADING)
|
||||
|
@ -3695,11 +3701,8 @@ void Surf_NewMap (void)
|
|||
if (!pe)
|
||||
Cvar_ForceCallback(&r_particlesystem);
|
||||
R_Clutter_Purge();
|
||||
TRACE(("dbg: Surf_NewMap: clear particles\n"));
|
||||
P_ClearParticles ();
|
||||
TRACE(("dbg: Surf_NewMap: wiping them stains (getting the cloth out)\n"));
|
||||
Surf_WipeStains();
|
||||
CL_RegisterParticles();
|
||||
TRACE(("dbg: Surf_NewMap: building lightmaps\n"));
|
||||
Surf_BuildLightmaps ();
|
||||
|
||||
|
@ -3710,7 +3713,6 @@ TRACE(("dbg: Surf_NewMap: ui\n"));
|
|||
#endif
|
||||
TRACE(("dbg: Surf_NewMap: tp\n"));
|
||||
TP_NewMap();
|
||||
R_SetSky(cl.skyname);
|
||||
|
||||
for (i = 0; i < cl.num_statics; i++)
|
||||
{
|
||||
|
@ -3751,6 +3753,8 @@ void Surf_PreNewMap(void)
|
|||
r_oldviewcluster = -1;
|
||||
r_viewcluster2 = -1;
|
||||
r_oldviewcluster2 = -1;
|
||||
|
||||
Shader_DoReload();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -370,7 +370,8 @@ extern uploadfmt_t lightmap_fmt; //bgra32, rgba32, rgb24, lum8
|
|||
void QDECL Surf_RebuildLightmap_Callback (struct cvar_s *var, char *oldvalue);
|
||||
|
||||
|
||||
void R_SetSky(char *skyname); /*override all sky shaders*/
|
||||
void R_SkyShutdown(void);
|
||||
void R_SetSky(const char *skyname);
|
||||
|
||||
#if defined(GLQUAKE)
|
||||
void GLR_Init (void);
|
||||
|
@ -634,6 +635,7 @@ extern cvar_t r_lightstylesmooth;
|
|||
extern cvar_t r_lightstylesmooth_limit;
|
||||
extern cvar_t r_lightstylespeed;
|
||||
extern cvar_t r_lightstylescale;
|
||||
extern cvar_t r_lightmap_scale;
|
||||
extern cvar_t gl_nocolors;
|
||||
extern cvar_t gl_load24bit;
|
||||
extern cvar_t gl_finish;
|
||||
|
@ -647,14 +649,15 @@ extern cvar_t r_meshpitch;
|
|||
|
||||
enum {
|
||||
RSPEED_TOTALREFRESH,
|
||||
RSPEED_CSQCPHYSICS,
|
||||
RSPEED_CSQCREDRAW,
|
||||
RSPEED_LINKENTITIES,
|
||||
RSPEED_PROTOCOL,
|
||||
RSPEED_WORLDNODE,
|
||||
RSPEED_WORLD,
|
||||
RSPEED_DRAWENTITIES,
|
||||
RSPEED_STENCILSHADOWS,
|
||||
RSPEED_FULLBRIGHTS,
|
||||
RSPEED_DYNAMIC,
|
||||
RSPEED_OPAQUE,
|
||||
RSPEED_RTLIGHTS,
|
||||
RSPEED_TRANSPARENTS,
|
||||
RSPEED_PROTOCOL,
|
||||
RSPEED_PARTICLES,
|
||||
RSPEED_PARTICLESDRAW,
|
||||
RSPEED_PALETTEFLASHES,
|
||||
|
|
|
@ -47,10 +47,7 @@ void QDECL SCR_Fov_Callback (struct cvar_s *var, char *oldvalue);
|
|||
void QDECL Image_TextureMode_Callback (struct cvar_s *var, char *oldvalue);
|
||||
void QDECL R_SkyBox_Changed (struct cvar_s *var, char *oldvalue)
|
||||
{
|
||||
if (qrenderer != QR_NONE && cl.worldmodel)
|
||||
{
|
||||
R_SetSky(cl.skyname);
|
||||
}
|
||||
Shader_NeedReload(false);
|
||||
}
|
||||
void R_ForceSky_f(void)
|
||||
{
|
||||
|
@ -58,7 +55,7 @@ void R_ForceSky_f(void)
|
|||
{
|
||||
extern cvar_t r_skyboxname;
|
||||
if (*r_skyboxname.string)
|
||||
Con_Printf("Current user skybox is %s\n", cl.skyname);
|
||||
Con_Printf("Current user skybox is %s\n", r_skyboxname.string);
|
||||
else if (*cl.skyname)
|
||||
Con_Printf("Current per-map skybox is %s\n", cl.skyname);
|
||||
else
|
||||
|
@ -66,8 +63,7 @@ void R_ForceSky_f(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
Q_strncpyz(cl.skyname, Cmd_Argv(1), sizeof(cl.skyname));
|
||||
R_SetSky(cl.skyname);
|
||||
R_SetSky(Cmd_Argv(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,6 +94,7 @@ static cvar_t gl_driver = CVARF ("gl_driver", "",
|
|||
cvar_t gl_shadeq1_name = CVARD ("gl_shadeq1_name", "*", "Rename all surfaces from quake1 bsps using this pattern for the purposes of shader names.");
|
||||
extern cvar_t r_vertexlight;
|
||||
extern cvar_t r_forceprogramify;
|
||||
extern cvar_t dpcompat_nopremulpics;
|
||||
|
||||
cvar_t mod_md3flags = CVARD ("mod_md3flags", "1", "The flags field of md3s was never officially defined. If this is set to 1, the flags will be treated identically to mdl files. Otherwise they will be ignored. Naturally, this is required to provide rotating pickups in quake.");
|
||||
|
||||
|
@ -126,7 +123,7 @@ cvar_t r_dynamic = CVARFD ("r_dynamic", IFMINIMAL("0","1"),
|
|||
cvar_t r_fastturb = CVARF ("r_fastturb", "0",
|
||||
CVAR_SHADERSYSTEM);
|
||||
cvar_t r_fastsky = CVARF ("r_fastsky", "0",
|
||||
CVAR_ARCHIVE | CVAR_SHADERSYSTEM);
|
||||
CVAR_ARCHIVE);
|
||||
cvar_t r_fastskycolour = CVARF ("r_fastskycolour", "0",
|
||||
CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
|
||||
cvar_t r_fb_bmodels = CVARAF("r_fb_bmodels", "1",
|
||||
|
@ -159,6 +156,7 @@ cvar_t r_lightstylesmooth = CVARF ("r_lightstylesmooth", "0", CVAR_ARCHIVE);
|
|||
cvar_t r_lightstylesmooth_limit = CVAR ("r_lightstylesmooth_limit", "2");
|
||||
cvar_t r_lightstylespeed = CVAR ("r_lightstylespeed", "10");
|
||||
cvar_t r_lightstylescale = CVAR ("r_lightstylescale", "1");
|
||||
cvar_t r_lightmap_scale = CVARFD ("r_shadow_realtime_nonworld_lightmaps", "1", 0, "Scaler for lightmaps used when not using realtime world lighting. Probably broken.");
|
||||
cvar_t r_hdr_irisadaptation = CVARF ("r_hdr_irisadaptation", "0", CVAR_ARCHIVE);
|
||||
cvar_t r_hdr_irisadaptation_multiplier = CVAR ("r_hdr_irisadaptation_multiplier", "2");
|
||||
cvar_t r_hdr_irisadaptation_minvalue = CVAR ("r_hdr_irisadaptation_minvalue", "0.5");
|
||||
|
@ -398,6 +396,7 @@ cvar_t gl_mipcap = CVARAFC("d_mipcap", "0 1000", "gl_miptexLevel",
|
|||
cvar_t gl_texturemode2d = CVARFCD("gl_texturemode2d", "GL_LINEAR",
|
||||
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK, Image_TextureMode_Callback,
|
||||
"Specifies how 2d images are sampled. format is a 3-tupple ");
|
||||
cvar_t r_font_linear = CVARF("r_font_linear", "1", CVAR_RENDERERLATCH);
|
||||
|
||||
cvar_t vid_triplebuffer = CVARAFD ("vid_triplebuffer", "1", "gl_triplebuffer", CVAR_ARCHIVE, "Specifies whether the hardware is forcing tripplebuffering on us, this is the number of extra page swaps required before old data has been completely overwritten.");
|
||||
|
||||
|
@ -435,7 +434,7 @@ cvar_t r_vertexdlights = CVARD ("r_vertexdlights", "0", "Determine model li
|
|||
|
||||
cvar_t vid_preservegamma = CVARD ("vid_preservegamma", "0", "Restore initial hardware gamma ramps when quitting.");
|
||||
cvar_t vid_hardwaregamma = CVARFD ("vid_hardwaregamma", "1",
|
||||
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Use hardware gamma ramps. 0=loadtime-gamma, 1=glsl(windowed) or hardware(fullscreen), 2=always glsl, 3=always hardware gamma.");
|
||||
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Use hardware gamma ramps. 0=ugly texture-based gamma, 1=glsl(windowed) or hardware(fullscreen), 2=always glsl, 3=always hardware gamma (disabled if hardware doesn't support).");
|
||||
cvar_t vid_desktopgamma = CVARFD ("vid_desktopgamma", "0",
|
||||
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Apply gamma ramps upon the desktop rather than the window.");
|
||||
|
||||
|
@ -816,6 +815,7 @@ void Renderer_Init(void)
|
|||
Cvar_Register(&r_lightstylesmooth_limit, GRAPHICALNICETIES);
|
||||
Cvar_Register(&r_lightstylespeed, GRAPHICALNICETIES);
|
||||
Cvar_Register(&r_lightstylescale, GRAPHICALNICETIES);
|
||||
Cvar_Register(&r_lightmap_scale, GRAPHICALNICETIES);
|
||||
|
||||
Cvar_Register(&r_hdr_irisadaptation, GRAPHICALNICETIES);
|
||||
Cvar_Register(&r_hdr_irisadaptation_multiplier, GRAPHICALNICETIES);
|
||||
|
@ -936,6 +936,7 @@ void Renderer_Init(void)
|
|||
Cvar_Register (&gl_miptexLevel, GRAPHICALNICETIES);
|
||||
Cvar_Register (&gl_texturemode, GLRENDEREROPTIONS);
|
||||
Cvar_Register (&gl_texturemode2d, GLRENDEREROPTIONS);
|
||||
Cvar_Register (&r_font_linear, GLRENDEREROPTIONS);
|
||||
Cvar_Register (&gl_mipcap, GLRENDEREROPTIONS);
|
||||
Cvar_Register (&gl_texture_anisotropic_filtering, GLRENDEREROPTIONS);
|
||||
Cvar_Register (&r_max_gpu_bones, GRAPHICALNICETIES);
|
||||
|
@ -965,6 +966,7 @@ void Renderer_Init(void)
|
|||
Cvar_Register (&r_polygonoffset_stencil_offset, GLRENDEREROPTIONS);
|
||||
|
||||
Cvar_Register (&r_forceprogramify, GLRENDEREROPTIONS);
|
||||
Cvar_Register (&dpcompat_nopremulpics, GLRENDEREROPTIONS);
|
||||
#ifdef VKQUAKE
|
||||
Cvar_Register (&vk_stagingbuffers, VKRENDEREROPTIONS);
|
||||
Cvar_Register (&vk_submissionthread, VKRENDEREROPTIONS);
|
||||
|
@ -1474,10 +1476,6 @@ TRACE(("dbg: R_ApplyRenderer: initing mods\n"));
|
|||
#ifndef CLIENTONLY
|
||||
if (sv.world.worldmodel)
|
||||
{
|
||||
#ifdef Q2SERVER
|
||||
q2edict_t *q2ent;
|
||||
#endif
|
||||
|
||||
TRACE(("dbg: R_ApplyRenderer: reloading server map\n"));
|
||||
sv.world.worldmodel = Mod_ForName (sv.modelname, MLV_WARNSYNC);
|
||||
TRACE(("dbg: R_ApplyRenderer: loaded\n"));
|
||||
|
@ -1507,6 +1505,7 @@ TRACE(("dbg: R_ApplyRenderer: clearing world\n"));
|
|||
#ifdef Q2SERVER
|
||||
else if (svs.gametype == GT_QUAKE2)
|
||||
{
|
||||
q2edict_t *q2ent;
|
||||
for (i = 0; i < Q2MAX_MODELS; i++)
|
||||
{
|
||||
if (sv.strings.configstring[Q2CS_MODELS+i] && *sv.strings.configstring[Q2CS_MODELS+i] && (!strcmp(sv.strings.configstring[Q2CS_MODELS+i] + strlen(sv.strings.configstring[Q2CS_MODELS+i]) - 4, ".bsp") || i-1 < sv.world.worldmodel->numsubmodels))
|
||||
|
|
|
@ -4239,11 +4239,39 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale
|
|||
if (!filedata)
|
||||
return NULL;
|
||||
|
||||
hasalpha = false;
|
||||
rgbadata_start = Read32BitImageFile(filedata, filelen, &width, &height, &hasalpha, "cursor");
|
||||
FS_FreeFile(filedata);
|
||||
if (!rgbadata_start)
|
||||
return NULL;
|
||||
|
||||
if (!hasalpha && !strchr(filename, ':'))
|
||||
{ //people seem to insist on using jpgs, which don't have alpha.
|
||||
//screw over the alpha channel if needed.
|
||||
unsigned int alpha_width, alpha_height, p;
|
||||
char aname[MAX_QPATH];
|
||||
unsigned char *alphadata;
|
||||
char *alph;
|
||||
size_t alphsize;
|
||||
char ext[8];
|
||||
COM_StripExtension(filename, aname, sizeof(aname));
|
||||
COM_FileExtension(filename, ext, sizeof(ext));
|
||||
Q_strncatz(aname, "_alpha.", sizeof(aname));
|
||||
Q_strncatz(aname, ext, sizeof(aname));
|
||||
alphsize = FS_LoadFile(filename, &alph);
|
||||
if (alph)
|
||||
{
|
||||
if ((alphadata = Read32BitImageFile(alph, alphsize, &alpha_width, &alpha_height, &hasalpha, aname)))
|
||||
{
|
||||
if (alpha_width == width && alpha_height == height)
|
||||
for (p = 0; p < alpha_width*alpha_height; p++)
|
||||
rgbadata_start[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3;
|
||||
BZ_Free(alphadata);
|
||||
}
|
||||
FS_FreeFile(alph);
|
||||
}
|
||||
}
|
||||
|
||||
if (scale != 1)
|
||||
{
|
||||
int nw,nh;
|
||||
|
|
|
@ -628,8 +628,10 @@ qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key)
|
|||
fname += 4;
|
||||
else if (!strncmp(fname, "source/", 7))
|
||||
fname += 7;
|
||||
else if (!strncmp(fname, "qcsrc/", 7))
|
||||
fname += 7;
|
||||
else if (!strncmp(fname, "qcsrc/", 6))
|
||||
fname += 6;
|
||||
else if (!strncmp(fname, "progs/", 6))
|
||||
fname += 6;
|
||||
|
||||
|
||||
cl = con->userline;
|
||||
|
@ -878,6 +880,9 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st
|
|||
return DEBUG_TRACE_OFF; //get lost
|
||||
}
|
||||
|
||||
if (!strncmp(filename, "./", 2))
|
||||
filename+=2;
|
||||
|
||||
//we can cope with no line info by displaying asm
|
||||
if (editormodal || !statement
|
||||
|| !line || *line == -1 //FIXME
|
||||
|
@ -960,10 +965,10 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st
|
|||
{
|
||||
if (fatal)
|
||||
{
|
||||
Con_Printf(CON_ERROR "Unable to find %s\n", filename);
|
||||
Con_Printf(CON_ERROR "Unable to find file \"%s\"\n", filename);
|
||||
return DEBUG_TRACE_ABORT;
|
||||
}
|
||||
Con_Printf(CON_WARNING "Unable to find %s\n", filename);
|
||||
Con_Printf(CON_WARNING "Unable to find file \"%s\"\n", filename);
|
||||
return DEBUG_TRACE_OFF; //whoops
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1948,8 +1948,9 @@ void R_DrawNameTags(void)
|
|||
score = DotProduct(diff, vpn);// r_refdef.viewaxis[0]);
|
||||
if (score > bestscore)
|
||||
{
|
||||
int hitent;
|
||||
vec3_t imp;
|
||||
if (CL_TraceLine(r_refdef.vieworg, org, imp, NULL, NULL)>=1)
|
||||
if (CL_TraceLine(r_refdef.vieworg, org, imp, NULL, &hitent)>=1 || hitent == i)
|
||||
{
|
||||
best = i;
|
||||
bestscore = score;
|
||||
|
|
|
@ -799,6 +799,7 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
|
|||
{
|
||||
char token[4096];
|
||||
char key[128];
|
||||
char skyname[128];
|
||||
const char *data = Mod_GetEntitiesString(wmodel);
|
||||
#ifdef PACKAGE_TEXWAD
|
||||
mapskys_t *msky;
|
||||
|
@ -815,10 +816,10 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
|
|||
#endif
|
||||
|
||||
// this hack is necessary to ensure Quake 2 maps get their default skybox, without breaking q1 etc
|
||||
if (wmodel->fromgame == fg_quake2)
|
||||
strcpy(cl.skyname, "unit1_");
|
||||
if (wmodel && wmodel->fromgame == fg_quake2)
|
||||
strcpy(skyname, "unit1_");
|
||||
else
|
||||
cl.skyname[0] = '\0';
|
||||
skyname[0] = '\0';
|
||||
|
||||
if (data)
|
||||
if ((data=COM_ParseOut(data, token, sizeof(token)))) //read the map info.
|
||||
|
@ -887,11 +888,11 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
|
|||
}
|
||||
else if (!strcmp("skyname", key)) // for HalfLife maps
|
||||
{
|
||||
Q_strncpyz(cl.skyname, token, sizeof(cl.skyname));
|
||||
Q_strncpyz(skyname, token, sizeof(skyname));
|
||||
}
|
||||
else if (!strcmp("sky", key)) // for Quake2 maps
|
||||
{
|
||||
Q_strncpyz(cl.skyname, token, sizeof(cl.skyname));
|
||||
Q_strncpyz(skyname, token, sizeof(skyname));
|
||||
}
|
||||
else if (!strcmp("skyrotate", key)) //q2 feature
|
||||
{
|
||||
|
@ -917,6 +918,8 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
|
|||
}
|
||||
}
|
||||
|
||||
if (wmodel)
|
||||
{
|
||||
COM_FileBase (wmodel->name, token, sizeof(token));
|
||||
|
||||
#ifdef PACKAGE_TEXWAD
|
||||
|
@ -925,9 +928,12 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
|
|||
{
|
||||
if (!strcmp(msky->mapname, token))
|
||||
{
|
||||
Q_strncpyz(cl.skyname, msky->skyname, sizeof(cl.skyname));
|
||||
Q_strncpyz(skyname, msky->skyname, sizeof(skyname));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
R_SetSky(skyname);
|
||||
}
|
||||
|
|
|
@ -261,6 +261,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define INTERQUAKEMODELS
|
||||
#define RAGDOLL
|
||||
|
||||
#define USEAREAGRID //world collision optimisation. REQUIRED for performance with xonotic. hopefully it helps a few other mods too.
|
||||
#define HUFFNETWORK //huffman network compression
|
||||
// #define PACKAGE_DOOMWAD //doom wad support (maps+sprites are separate)
|
||||
// #define MAP_DOOM //doom map support
|
||||
|
@ -312,7 +313,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#define PSET_SCRIPT
|
||||
#define PSET_CLASSIC
|
||||
//#define PSET_DARKPLACES
|
||||
|
||||
|
||||
#define HAVE_CDPLAYER //includes cd playback. actual cds. faketracks are supported regardless.
|
||||
|
@ -378,7 +378,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define DISTRIBUTIONLONG "Forethought Entertainment" //effectively the 'company' name
|
||||
#endif
|
||||
#ifndef FULLENGINENAME
|
||||
#define FULLENGINENAME "FTE QuakeWorld" //the posh name for the engine
|
||||
#define FULLENGINENAME "FTE Quake" //the posh name for the engine
|
||||
#endif
|
||||
#ifndef ENGINEWEBSITE
|
||||
#define ENGINEWEBSITE "http://fte.triptohell.info" //url for program
|
||||
|
|
|
@ -47,7 +47,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
//#define MAX_MAP_LIGHTING 0x100000
|
||||
//#define MAX_MAP_VISIBILITY 0x200000
|
||||
|
||||
#define SANITY_MAX_MAP_BRUSHSIDES 0x100000
|
||||
#define SANITY_MAX_MAP_BRUSHSIDES ((~0u)/sizeof(q2cbrushside_t))
|
||||
|
||||
// key / value pair sizes
|
||||
|
||||
|
@ -371,13 +371,13 @@ typedef struct q2miptex_s
|
|||
// 16 bit short limits
|
||||
#define SANITY_MAX_Q2MAP_MODELS 1024
|
||||
//#define MAX_Q2MAP_ENTITIES 2048
|
||||
#define SANITY_MAX_MAP_BRUSHES 0x10000
|
||||
#define SANITY_MAX_MAP_BRUSHES (~0u/sizeof(*out))
|
||||
#define SANITY_MAX_MAP_LEAFFACES 262144 //sanity only
|
||||
|
||||
#define MAX_Q2MAP_AREAS 256
|
||||
#define MAX_Q2MAP_AREAPORTALS 1024
|
||||
//#define MAX_Q2MAP_VERTS MAX_MAP_VERTS
|
||||
//#define MAX_Q2MAP_FACES MAX_MAP_FACES
|
||||
#define SANITY_MAX_MAP_LEAFFACES 262144 //sanity only
|
||||
#ifdef FTE_TARGET_WEB
|
||||
#define MAX_Q2MAP_LEAFBRUSHES (32768) //used in an array
|
||||
#else
|
||||
|
|
|
@ -1370,22 +1370,14 @@ const char *Cmd_ExpandCvar(char *cvarterm, int maxaccesslevel, int *newaccesslev
|
|||
int quotetype = 0;
|
||||
const char *cvarname;
|
||||
|
||||
cvarname = cvarterm;
|
||||
if (*cvarterm == '{')
|
||||
{ //set foo ba"r; ${foo q} -> ba\"r
|
||||
//set foo ba"r; ${foo q} -> ba\"r
|
||||
//set foo bar; ${foo asis} -> ba"r
|
||||
//${bar q} -> <EMPTY>
|
||||
//${bar ?} -> ""
|
||||
//${bar !} -> <ERROR>
|
||||
fixup = &cvarterm[strlen(cvarterm)-1];
|
||||
if (*fixup != '}')
|
||||
return NULL;
|
||||
cvarterm++;
|
||||
fixval = *fixup;
|
||||
*fixup = 0;
|
||||
termlen = fixup - cvarname;
|
||||
if (fixval)
|
||||
termlen++;
|
||||
fixup = cvarterm+strlen(cvarterm);
|
||||
fixval = 0;
|
||||
termlen = fixup - cvarterm;
|
||||
if (fixup-cvarterm > 2 && !strncmp(fixup-2, " ?", 2))
|
||||
{ //force expansion, even if not defined.
|
||||
pl = 2;
|
||||
|
@ -1409,29 +1401,20 @@ const char *Cmd_ExpandCvar(char *cvarterm, int maxaccesslevel, int *newaccesslev
|
|||
else
|
||||
{
|
||||
pl = 0;
|
||||
quotetype = 1; //default to escaping.
|
||||
quotetype = dpcompat_console.ival; //default to escaping.
|
||||
}
|
||||
if (pl)
|
||||
{
|
||||
*fixup = fixval;
|
||||
fixup -= pl;
|
||||
fixval = *fixup;
|
||||
*fixup = 0;
|
||||
}
|
||||
else
|
||||
fixup = NULL;
|
||||
if (*cvarterm == '$')
|
||||
cvarname = Cmd_ExpandCvar(cvarterm+1, maxaccesslevel, newaccesslevel, &pl);
|
||||
else
|
||||
cvarname = cvarterm;
|
||||
}
|
||||
else
|
||||
{
|
||||
fixup = &cvarterm[strlen(cvarterm)];
|
||||
fixval = *fixup;
|
||||
|
||||
termlen = fixup - cvarname;
|
||||
if (fixval)
|
||||
termlen++;
|
||||
}
|
||||
|
||||
result = strtoul(cvarname, &t, 10);
|
||||
if ((dpcompat_console.ival||fixval) && (*t == 0 || (*t == '-' && t[1] == 0))) //only expand $0 if its actually ${0} - this avoids conflicting with the $0 macro
|
||||
|
@ -1470,6 +1453,8 @@ const char *Cmd_ExpandCvar(char *cvarterm, int maxaccesslevel, int *newaccesslev
|
|||
*newaccesslevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (fixup)
|
||||
*fixup = fixval;
|
||||
|
||||
if (quotetype == 3)
|
||||
|
@ -1524,7 +1509,44 @@ char *Cmd_ExpandString (const char *data, char *dest, int destlen, int *accessle
|
|||
if (c == '$' && (!(quotes&1) || dpcompat_console.ival))
|
||||
{
|
||||
data++;
|
||||
|
||||
if (*data == '$')
|
||||
{ //double-dollar expands to a single dollar.
|
||||
data++;
|
||||
str = "$";
|
||||
striptrailing = false;
|
||||
name_length = 0;
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
}
|
||||
else if (*data == '{')
|
||||
{ //${foo} can do some especially weird expansions.
|
||||
data++;
|
||||
i = 0;
|
||||
buf[i++] = '{';
|
||||
striptrailing = (*data == '-')?true:false;
|
||||
while (*data && *data != '}')
|
||||
{
|
||||
if (i < sizeof(buf)-2)
|
||||
buf[i++] = *data;
|
||||
data++;
|
||||
}
|
||||
buf[i] = 0;
|
||||
bestvar = NULL;
|
||||
if (expandcvars && (str = Cmd_ExpandCvar(buf+1+striptrailing, maxaccesslevel, accesslevel, &var_length)))
|
||||
bestvar = str;
|
||||
if (expandmacros && (str = TP_MacroString (buf+1+striptrailing, accesslevel, &var_length)))
|
||||
bestvar = str;
|
||||
str = bestvar;
|
||||
if (*data == '}')
|
||||
{
|
||||
data++;
|
||||
buf[i++] = '}';
|
||||
buf[i] = 0;
|
||||
}
|
||||
name_length = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
striptrailing = (*data == '-')?true:false;
|
||||
|
||||
// Copy the text after '$' to a temp buffer
|
||||
|
@ -1535,17 +1557,10 @@ char *Cmd_ExpandString (const char *data, char *dest, int destlen, int *accessle
|
|||
var_length = 0;
|
||||
while((c = *data))
|
||||
{
|
||||
if (c < ' ')
|
||||
if (c < ' ' || c == '$')
|
||||
break;
|
||||
if (c == ' ' && buf[0] != '{')
|
||||
break;
|
||||
if (c == '$' && i == 0)
|
||||
{
|
||||
data++;
|
||||
name_length = 0;
|
||||
str = "$";
|
||||
break;
|
||||
}
|
||||
data++;
|
||||
buf[i++] = c;
|
||||
buf[i] = 0;
|
||||
|
@ -1565,6 +1580,7 @@ char *Cmd_ExpandString (const char *data, char *dest, int destlen, int *accessle
|
|||
str = NULL;
|
||||
name_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (str)
|
||||
{
|
||||
|
@ -2406,7 +2422,7 @@ void Cmd_ForwardToServer_f (void)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
if (Q_strcasecmp(Cmd_Argv(1), "pext") == 0 && (cls.protocol != CP_NETQUAKE || cls.protocol_nq != CPNQ_ID || cls.proquake_angles_hack || cls.netchan.remote_address.type != NA_LOOPBACK))
|
||||
if (Q_strcasecmp(Cmd_Argv(1), "pext") == 0 && (cls.protocol != CP_NETQUAKE || cls.fteprotocolextensions2 || cls.protocol_nq != CPNQ_ID || cls.proquake_angles_hack || cls.netchan.remote_address.type != NA_LOOPBACK))
|
||||
{ //don't send any extension flags this if we're using cl_loopbackprotocol nqid, purely for a compat test.
|
||||
//if you want to record compat-demos, disable extensions instead.
|
||||
unsigned int fp1 = Net_PextMask(1, cls.protocol == CP_NETQUAKE), fp2 = Net_PextMask(2, cls.protocol == CP_NETQUAKE);
|
||||
|
@ -2466,7 +2482,7 @@ void Cmd_ExecuteString (const char *text, int level)
|
|||
; //certain commands don't get pre-expanded in dp. evil hack. quote them to pre-expand anyway. double evil.
|
||||
else
|
||||
text = Cmd_ExpandString(text, dest, sizeof(dest), &level, !Cmd_IsInsecure()?true:false, true);
|
||||
Cmd_TokenizeString (text, level == RESTRICT_LOCAL?true:false, false);
|
||||
Cmd_TokenizeString (text, (level == RESTRICT_LOCAL&&!dpcompat_console.ival)?true:false, false);
|
||||
|
||||
// execute the command line
|
||||
if (!Cmd_Argc())
|
||||
|
@ -3898,6 +3914,13 @@ static char *Macro_Version (void)
|
|||
q2 servers checking for cheats. */
|
||||
return va("%.2f %s", 2.57, version_string());
|
||||
}
|
||||
static char *Macro_Dedicated (void)
|
||||
{
|
||||
if (isDedicated)
|
||||
return "1";
|
||||
else
|
||||
return "0";
|
||||
}
|
||||
static char *Macro_Quote (void)
|
||||
{
|
||||
return "\"";
|
||||
|
@ -3973,6 +3996,7 @@ void Cmd_Init (void)
|
|||
Cmd_AddMacro("properdate", Macro_ProperDate, false);
|
||||
Cmd_AddMacro("version", Macro_Version, false);
|
||||
Cmd_AddMacro("qt", Macro_Quote, false);
|
||||
Cmd_AddMacro("dedicated", Macro_Dedicated, false);
|
||||
|
||||
Cvar_Register(&tp_disputablemacros, "Teamplay");
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ void Mod_UpdateCRC(void *ctx, void *data, size_t a, size_t b)
|
|||
if (strcmp(st, Info_ValueForKey(cls.userinfo[0], ctx)))
|
||||
{
|
||||
Info_SetValueForKey (cls.userinfo[0], ctx, st, sizeof(cls.userinfo[0]));
|
||||
if (cls.state >= ca_connected)
|
||||
if (cls.state >= ca_connected && (cls.protocol == CP_QUAKEWORLD || (cls.fteprotocolextensions2 & PEXT2_PREDINFO)))
|
||||
CL_SendClientCommand(true, "setinfo %s %s", (char*)ctx, st);
|
||||
}
|
||||
}
|
||||
|
@ -2519,6 +2519,7 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
|||
char fname[MAX_QPATH];
|
||||
char tok[64];
|
||||
size_t fsize;
|
||||
com_tokentype_t ttype;
|
||||
Q_snprintfz(fname, sizeof(fname), "%s.framegroups", modelname);
|
||||
line = file = COM_LoadFile(fname, 5, &fsize);
|
||||
if (!file)
|
||||
|
@ -2546,7 +2547,11 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
|||
frames[count].loop = true;
|
||||
else
|
||||
frames[count].loop = !!atoi(tok);
|
||||
line = COM_ParseOut(line, frames[count].name, sizeof(frames[count].name));
|
||||
line = COM_ParseType(line, tok, sizeof(tok), &ttype);
|
||||
if (ttype != TTP_EOF)
|
||||
Q_strncpyz(frames[count].name, tok, sizeof(frames[count].name));
|
||||
else
|
||||
Q_snprintfz(frames[count].name, sizeof(frames[count].name), "groupified_%d_anim", count); //to match DP. frameforname cares.
|
||||
if (frames[count].posecount>0 && frames[count].fps)
|
||||
count++;
|
||||
|
||||
|
@ -4518,8 +4523,16 @@ int Mod_TagNumForName(model_t *model, const char *name)
|
|||
|
||||
if (!model)
|
||||
return 0;
|
||||
if (model->loadstate != MLS_LOADED)
|
||||
{
|
||||
if (model->loadstate == MLS_NOTLOADED)
|
||||
Mod_LoadModel(model, MLV_SILENT);
|
||||
if (model->loadstate == MLS_LOADING)
|
||||
COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING);
|
||||
if (model->loadstate != MLS_LOADED)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HALFLIFEMODELS
|
||||
if (model->type == mod_halflife)
|
||||
return HLMDL_BoneForName(model, name);
|
||||
|
@ -4624,8 +4637,15 @@ int Mod_SkinNumForName(model_t *model, int surfaceidx, const char *name)
|
|||
galiasinfo_t *inf;
|
||||
galiasskin_t *skin;
|
||||
|
||||
if (!model || model->type != mod_alias)
|
||||
if (!model || model->loadstate != MLS_LOADED)
|
||||
{
|
||||
if (model && model->loadstate == MLS_NOTLOADED)
|
||||
Mod_LoadModel(model, MLV_SILENT);
|
||||
if (model && model->loadstate == MLS_LOADING)
|
||||
COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING);
|
||||
if (!model || model->loadstate != MLS_LOADED || model->type != mod_alias)
|
||||
return -1;
|
||||
}
|
||||
inf = Mod_Extradata(model);
|
||||
|
||||
while(surfaceidx-->0 && inf)
|
||||
|
@ -4648,8 +4668,15 @@ const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num)
|
|||
galiasanimation_t *group;
|
||||
galiasinfo_t *inf;
|
||||
|
||||
if (!model)
|
||||
if (!model || model->loadstate != MLS_LOADED)
|
||||
{
|
||||
if (model && model->loadstate == MLS_NOTLOADED)
|
||||
Mod_LoadModel(model, MLV_SILENT);
|
||||
if (model && model->loadstate == MLS_LOADING)
|
||||
COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING);
|
||||
if (!model || model->loadstate != MLS_LOADED)
|
||||
return NULL;
|
||||
}
|
||||
if (model->type == mod_alias)
|
||||
{
|
||||
inf = Mod_Extradata(model);
|
||||
|
@ -4674,8 +4701,15 @@ qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **nam
|
|||
galiasanimation_t *group;
|
||||
galiasinfo_t *inf;
|
||||
|
||||
if (!model)
|
||||
if (!model || model->loadstate != MLS_LOADED)
|
||||
{
|
||||
if (model && model->loadstate == MLS_NOTLOADED)
|
||||
Mod_LoadModel(model, MLV_SILENT);
|
||||
if (model && model->loadstate == MLS_LOADING)
|
||||
COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING);
|
||||
if (!model || model->loadstate != MLS_LOADED)
|
||||
return false;
|
||||
}
|
||||
if (model->type == mod_alias)
|
||||
{
|
||||
inf = Mod_Extradata(model);
|
||||
|
@ -4706,12 +4740,18 @@ shader_t *Mod_ShaderForSkin(model_t *model, int surfaceidx, int num)
|
|||
galiasinfo_t *inf;
|
||||
galiasskin_t *skin;
|
||||
|
||||
if (!model || model->type != mod_alias)
|
||||
if (!model || model->loadstate != MLS_LOADED)
|
||||
{
|
||||
if (model->type == mod_brush && surfaceidx < model->numtextures && !num)
|
||||
return model->textures[surfaceidx]->shader;
|
||||
if (model && model->loadstate == MLS_NOTLOADED)
|
||||
Mod_LoadModel(model, MLV_SILENT);
|
||||
if (model && model->loadstate == MLS_LOADING)
|
||||
COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING);
|
||||
if (!model || model->loadstate != MLS_LOADED)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (model->type == mod_alias)
|
||||
{
|
||||
inf = Mod_Extradata(model);
|
||||
|
||||
while(surfaceidx-->0 && inf)
|
||||
|
@ -4722,6 +4762,11 @@ shader_t *Mod_ShaderForSkin(model_t *model, int surfaceidx, int num)
|
|||
skin = inf->ofsskins;
|
||||
return skin[num].frame[0].shader;
|
||||
}
|
||||
else if (model->type == mod_brush && surfaceidx < model->numtextures && !num)
|
||||
return model->textures[surfaceidx]->shader;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num)
|
||||
{
|
||||
|
|
|
@ -179,6 +179,14 @@ typedef struct link_s
|
|||
struct link_s *prev, *next;
|
||||
} link_t;
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
typedef struct
|
||||
{
|
||||
link_t l;
|
||||
void *ed;
|
||||
} areagridlink_t;
|
||||
#endif
|
||||
|
||||
|
||||
void ClearLink (link_t *l);
|
||||
void RemoveLink (link_t *l);
|
||||
|
|
|
@ -794,7 +794,7 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
|
|||
Info_SetValueForKey (cls.userinfo[0], var->name, value, sizeof(cls.userinfo[0]));
|
||||
if (cls.state >= ca_connected)
|
||||
{
|
||||
#ifdef Q2CLIENT
|
||||
#if defined(Q2CLIENT) || defined(Q3CLIENT)
|
||||
if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) //q2 just resends the lot. Kinda bad...
|
||||
{
|
||||
cls.resendinfo = true;
|
||||
|
|
|
@ -786,7 +786,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
|
|||
|| !Q_strcasecmp(link, "ent") || !Q_strcasecmp(link, "rtlights")
|
||||
|| !Q_strcasecmp(link, "shader") || !Q_strcasecmp(link, "framegroups"))
|
||||
Q_snprintfz(link, sizeof(link), "\\edit\\%s", name);
|
||||
else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx")|| !Q_strcasecmp(link, "bmp"))
|
||||
else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx") || !Q_strcasecmp(link, "bmp") || !Q_strcasecmp(link, "dds"))
|
||||
{
|
||||
//FIXME: image replacements are getting in the way here.
|
||||
Q_snprintfz(link, sizeof(link), "\\tiprawimg\\%s\\tip\\(note: image replacement rules are context-dependant, including base path, sub path, extension, or complete replacement via a shader)", name);
|
||||
|
@ -3026,7 +3026,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
|
|||
/*stuff that makes dp-only mods work a bit better*/
|
||||
#define DPCOMPAT QCFG "gl_specular 1\nset _cl_playermodel \"\"\n set dpcompat_set 1\ndpcompat_console 1\nset dpcompat_corruptglobals 1\nset vid_pixelheight 1\n"
|
||||
/*nexuiz/xonotic has a few quirks/annoyances...*/
|
||||
#define NEXCFG DPCOMPAT "cl_nopred 1\ncl_loopbackprotocol dpp7\nset sv_listen_dp 1\nset sv_listen_qw 0\nset sv_listen_nq 0\nset dpcompat_nopreparse 1\nset r_particlesdesc effectinfo\nset sv_bigcoords 1\nset sv_maxairspeed \"400\"\nset sv_jumpvelocity 270\nset sv_mintic \"0.01\"\ncl_nolerp 0\npr_enable_uriget 0\n"
|
||||
#define NEXCFG DPCOMPAT "cl_nopred 1\ncl_loopbackprotocol dpp7\nset sv_listen_dp 1\nset sv_listen_qw 0\nset sv_listen_nq 0\nset dpcompat_nopreparse 1\nset r_particlesdesc effectinfo\nset sv_bigcoords 1\nset sv_maxairspeed \"30\"\nset sv_jumpvelocity 270\nset sv_mintic \"0.01\"\ncl_nolerp 0\npr_enable_uriget 0\n"
|
||||
#define XONCFG NEXCFG "set qport $qport_\ncom_parseutf8 1\npr_fixbrokenqccarrays 2\n"
|
||||
/*some modern non-compat settings*/
|
||||
#define DMFCFG "set com_parseutf8 1\npm_airstep 1\nsv_demoExtensions 1\n"
|
||||
|
|
|
@ -4115,6 +4115,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
|
|||
i = header.lumps[Q3LUMP_LIGHTMAPS].filelen / (mod->lightmaps.width*mod->lightmaps.height*3);
|
||||
mod->lightmaps.deluxemapping = !(i&1);
|
||||
mod->lightmaps.count = max(mod->lightmaps.count, i);
|
||||
mod->lightmaps.deluxemapping_modelspace = true; //we assume true for q3bsp.
|
||||
|
||||
for (i = 0; i < mod->numsurfaces && mod->lightmaps.deluxemapping; i++)
|
||||
{
|
||||
|
@ -4159,6 +4160,28 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
|
|||
mod->funcs.NativeContents = CM_NativeContents;
|
||||
|
||||
#ifndef SERVERONLY
|
||||
{
|
||||
char deluxeMaps[64], *key;
|
||||
key = (char*)Mod_ParseWorldspawnKey(mod, "deluxeMaps", deluxeMaps, sizeof(deluxeMaps));
|
||||
if (*key)
|
||||
{
|
||||
switch(atoi(key))
|
||||
{
|
||||
case 0:
|
||||
mod->lightmaps.deluxemapping = false;
|
||||
break;
|
||||
case 1:
|
||||
// mod->lightmaps.deluxemapping = true;
|
||||
mod->lightmaps.deluxemapping_modelspace = true;
|
||||
break;
|
||||
case 2:
|
||||
// mod->lightmaps.deluxemapping = true;
|
||||
mod->lightmaps.deluxemapping_modelspace = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//light grid info
|
||||
if (mod->lightgrid)
|
||||
{
|
||||
|
@ -6600,7 +6623,4 @@ void CM_Init(void) //register cvars.
|
|||
|
||||
CM_InitBoxHull ();
|
||||
}
|
||||
void CM_Shutdown(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,7 @@ static char *cvargroup_progs = "Progs variables";
|
|||
|
||||
cvar_t sv_gameplayfix_nolinknonsolid = CVARD("sv_gameplayfix_nolinknonsolid", "1", "When 0, setorigin et al will not link the entity into the collision nodes (which is faster, especially if you have a lot of non-solid entities. When 1, allows entities to freely switch between .solid values (except for SOLID_BSP) without relinking. A lot of DP mods assume a value of 1 and will bug out otherwise, while 0 will restore a bugs present in various mods.");
|
||||
cvar_t sv_gameplayfix_blowupfallenzombies = CVARD("sv_gameplayfix_blowupfallenzombies", "0", "Allow findradius to find non-solid entities. This may break certain mods.");
|
||||
cvar_t dpcompat_findradiusarealinks = CVARD("dpcompat_findradiusarealinks", "0", "Use the world collision info to accelerate findradius instead of looping through every single entity. May actually be slower for large radiuses, or fail to find entities which have not been linked properly with setorigin.");
|
||||
cvar_t pr_droptofloorunits = CVARD("pr_droptofloorunits", "256", "Distance that droptofloor is allowed to drop to be considered successul.");
|
||||
cvar_t pr_brokenfloatconvert = CVAR("pr_brokenfloatconvert", "0");
|
||||
cvar_t pr_fixbrokenqccarrays = CVARFD("pr_fixbrokenqccarrays", "0", CVAR_LATCH, "As part of its nq/qw/h2/csqc support, FTE remaps QC fields to match an internal order. This is a faster way to handle extended fields. However, some QCCs are buggy and don't report all field defs.\n0: do nothing. QCC must be well behaved.\n1: Duplicate engine fields, remap the ones we can to known offsets. This is sufficient for QCCX/FrikQCC mods that use hardcoded or even occasional calculated offsets (fixes ktpro).\n2: Scan the mod for field accessing instructions, and assume those are the fields (and that they don't alias non-fields). This can be used to work around gmqcc's WTFs (fixes xonotic).");
|
||||
|
@ -45,6 +46,7 @@ void PF_Common_RegisterCvars(void)
|
|||
|
||||
Cvar_Register (&sv_gameplayfix_blowupfallenzombies, cvargroup_progs);
|
||||
Cvar_Register (&sv_gameplayfix_nolinknonsolid, cvargroup_progs);
|
||||
Cvar_Register (&dpcompat_findradiusarealinks, cvargroup_progs);
|
||||
Cvar_Register (&pr_droptofloorunits, cvargroup_progs);
|
||||
Cvar_Register (&pr_brokenfloatconvert, cvargroup_progs);
|
||||
Cvar_Register (&pr_tempstringcount, cvargroup_progs);
|
||||
|
@ -64,6 +66,18 @@ void PF_Common_RegisterCvars(void)
|
|||
WPhys_Init();
|
||||
}
|
||||
|
||||
qofs_t PR_ReadBytesString(char *str)
|
||||
{
|
||||
size_t u = strtoul(str, &str, 0);
|
||||
if (*str == 'g')
|
||||
u *= 1024*1024*1024;
|
||||
if (*str == 'm')
|
||||
u *= 1024*1024;
|
||||
if (*str == 'k')
|
||||
u *= 1024;
|
||||
return u;
|
||||
}
|
||||
|
||||
//just prints out a warning with stack trace. so I can throttle spammy stack traces.
|
||||
static void PF_Warningf(pubprogfuncs_t *prinst, const char *fmt, ...)
|
||||
{
|
||||
|
@ -1895,6 +1909,8 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
int i;
|
||||
size_t insize;
|
||||
|
||||
Con_DPrintf("qcfopen(\"%s\", %i) called\n", name, fmode);
|
||||
|
||||
for (i = 0; i < MAX_QC_FILES; i++)
|
||||
if (!pf_fopen_files[i].data)
|
||||
break;
|
||||
|
@ -2849,10 +2865,14 @@ Returns a chain of entities that have origins within a spherical area
|
|||
findradius (origin, radius)
|
||||
=================
|
||||
*/
|
||||
#define AREA_ALL 0
|
||||
#define AREA_SOLID 1
|
||||
#define AREA_TRIGGER 2
|
||||
void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
world_t *w = prinst->parms->user;
|
||||
extern cvar_t sv_gameplayfix_blowupfallenzombies;
|
||||
extern cvar_t dpcompat_findradiusarealinks;
|
||||
wedict_t *ent, *chain;
|
||||
float rad;
|
||||
float *org;
|
||||
|
@ -2864,13 +2884,45 @@ void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
|
|||
|
||||
org = G_VECTOR(OFS_PARM0);
|
||||
rad = G_FLOAT(OFS_PARM1);
|
||||
rad = rad*rad;
|
||||
|
||||
if (prinst->callargc > 2)
|
||||
f = G_INT(OFS_PARM2)+prinst->fieldadjust;
|
||||
else
|
||||
f = &((comentvars_t*)NULL)->chain - (int*)NULL;
|
||||
|
||||
if (dpcompat_findradiusarealinks.ival)
|
||||
{
|
||||
static wedict_t *nearent[32768];
|
||||
vec3_t mins, maxs;
|
||||
int numents;
|
||||
extern int World_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, wedict_t **list, int maxcount, int areatype);
|
||||
|
||||
mins[0] = org[0] - rad;
|
||||
mins[1] = org[1] - rad;
|
||||
mins[2] = org[2] - rad;
|
||||
maxs[0] = org[0] + rad;
|
||||
maxs[1] = org[1] + rad;
|
||||
maxs[2] = org[2] + rad;
|
||||
|
||||
numents = World_AreaEdicts(w, mins, maxs, nearent, countof(nearent), AREA_ALL);
|
||||
rad = rad*rad;
|
||||
for (i=0 ; i<numents ; i++)
|
||||
{
|
||||
ent = nearent[i];
|
||||
if (ent->v->solid == SOLID_NOT && (!((int)ent->v->flags & FL_FINDABLE_NONSOLID)) && !sv_gameplayfix_blowupfallenzombies.value)
|
||||
continue;
|
||||
for (j=0 ; j<3 ; j++)
|
||||
eorg[j] = org[j] - (ent->v->origin[j] + (ent->v->mins[j] + ent->v->maxs[j])*0.5);
|
||||
if (DotProduct(eorg,eorg) > rad)
|
||||
continue;
|
||||
|
||||
((int*)ent->v)[f] = EDICT_TO_PROG(prinst, chain);
|
||||
chain = ent;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rad = rad*rad;
|
||||
for (i=1 ; i<w->num_edicts ; i++)
|
||||
{
|
||||
ent = WEDICT_NUM(prinst, i);
|
||||
|
@ -2886,6 +2938,7 @@ void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
|
|||
((int*)ent->v)[f] = EDICT_TO_PROG(prinst, chain);
|
||||
chain = ent;
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_EDICT(prinst, chain);
|
||||
}
|
||||
|
@ -4903,6 +4956,41 @@ void QCBUILTIN PF_crossproduct (pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
|
||||
//Maths functions
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NOLEGACY
|
||||
unsigned int FTEToDPContents(unsigned int contents)
|
||||
{
|
||||
unsigned int r = 0;
|
||||
if (contents & FTECONTENTS_SOLID)
|
||||
r |= DPCONTENTS_SOLID;
|
||||
if (contents & FTECONTENTS_WATER)
|
||||
r |= DPCONTENTS_WATER;
|
||||
if (contents & FTECONTENTS_SLIME)
|
||||
r |= DPCONTENTS_SLIME;
|
||||
if (contents & FTECONTENTS_LAVA)
|
||||
r |= DPCONTENTS_LAVA;
|
||||
if (contents & FTECONTENTS_SKY)
|
||||
r |= DPCONTENTS_SKY;
|
||||
if (contents & FTECONTENTS_BODY)
|
||||
r |= DPCONTENTS_BODY;
|
||||
if (contents & FTECONTENTS_CORPSE)
|
||||
r |= DPCONTENTS_CORPSE;
|
||||
if (contents & Q3CONTENTS_NODROP)
|
||||
r |= DPCONTENTS_NODROP;
|
||||
if (contents & FTECONTENTS_PLAYERCLIP)
|
||||
r |= DPCONTENTS_PLAYERCLIP;
|
||||
if (contents & FTECONTENTS_MONSTERCLIP)
|
||||
r |= DPCONTENTS_MONSTERCLIP;
|
||||
if (contents & Q3CONTENTS_DONOTENTER)
|
||||
r |= DPCONTENTS_DONOTENTER;
|
||||
if (contents & Q3CONTENTS_BOTCLIP)
|
||||
r |= DPCONTENTS_BOTCLIP;
|
||||
// if (contents & FTECONTENTS_OPAQUE)
|
||||
// r |= DPCONTENTS_OPAQUE;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
===============
|
||||
PF_droptofloor
|
||||
|
@ -5742,7 +5830,7 @@ finished:
|
|||
|
||||
void QCBUILTIN PF_sprintf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
char outbuf[4096];
|
||||
char outbuf[65536]; //FIXME: no idea how big this actually needs to be.
|
||||
PF_sprintf_internal(prinst, pr_globals, PR_GetStringOfs(prinst, OFS_PARM0), 1, outbuf, sizeof(outbuf));
|
||||
RETURN_TSTRING(outbuf);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ extern "C" {
|
|||
#include "progtype.h"
|
||||
#include "progslib.h"
|
||||
|
||||
#define AREAGRIDPERENT 16
|
||||
|
||||
struct wedict_s
|
||||
{
|
||||
enum ereftype_e ereftype;
|
||||
|
@ -21,7 +23,12 @@ struct wedict_s
|
|||
};
|
||||
#endif
|
||||
/*the above is shared with qclib*/
|
||||
#ifdef USEAREAGRID
|
||||
areagridlink_t gridareas[AREAGRIDPERENT]; //on overflow, use the inefficient overflow list.
|
||||
size_t gridareasequence; //used to avoid iterrating the same ent twice.
|
||||
#else
|
||||
link_t area;
|
||||
#endif
|
||||
pvscache_t pvsinfo;
|
||||
int lastruntime;
|
||||
int solidsize;
|
||||
|
@ -516,6 +523,10 @@ void PF_WriteString_Internal (int target, const char *str);
|
|||
pbool QDECL ED_CanFree (edict_t *ed);
|
||||
#endif
|
||||
|
||||
#ifndef NOLEGACY
|
||||
unsigned int FTEToDPContents(unsigned int contents);
|
||||
#endif
|
||||
|
||||
#define MOVETYPE_NONE 0 // never moves
|
||||
#define MOVETYPE_ANGLENOCLIP 1
|
||||
#define MOVETYPE_ANGLECLIP 2
|
||||
|
@ -589,6 +600,8 @@ typedef struct
|
|||
} rbeplugfuncs_t;
|
||||
#define RBEPLUGFUNCS_VERSION 1
|
||||
|
||||
qofs_t PR_ReadBytesString(char *str);
|
||||
|
||||
|
||||
#define DAMAGE_NO 0
|
||||
#define DAMAGE_YES 1
|
||||
|
|
|
@ -1082,22 +1082,22 @@ typedef struct entity_state_s
|
|||
qbyte basebone;
|
||||
qbyte pad;
|
||||
|
||||
unsigned int skinnum; /*q2 needs 32 bits, which is quite impressive*/
|
||||
unsigned int skinnum; /*for q2 this often contains rgba*/
|
||||
|
||||
unsigned short colormap;
|
||||
qbyte glowsize;
|
||||
qbyte glowcolour;
|
||||
|
||||
qbyte scale;
|
||||
qbyte scale; //4.4 precision
|
||||
char fatness;
|
||||
qbyte hexen2flags;
|
||||
qbyte abslight;
|
||||
|
||||
qbyte dpflags;
|
||||
qbyte colormod[3];//multiply this by 8 to read as 0 to 1...
|
||||
qbyte colormod[3];//3.5 precision
|
||||
|
||||
qbyte glowmod[3];
|
||||
qbyte trans;
|
||||
qbyte glowmod[3]; //3.5 precision
|
||||
qbyte trans; //254==1, 255==1-or-wateralpha
|
||||
|
||||
unsigned short light[4];
|
||||
|
||||
|
|
|
@ -132,6 +132,28 @@ typedef struct q2trace_s
|
|||
#define MOVE_OTHERONLY (1<<8) //test the trace against a single entity, ignoring non-solid/owner/etc flags (but respecting contents).
|
||||
#define MOVE_IGNOREHULL (1u<<31) //used on tracelines etc to simplify the code a little
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
//this macro does it in two steps to avoid float precision issues.
|
||||
//it also ensures that it will return at least one grid section.
|
||||
#define CALCAREAGRIDBOUNDS(w,min,max) \
|
||||
ming[0] = floor(((min)[0]+(w)->gridbias[0]) / (w)->gridscale[0]); \
|
||||
ming[1] = floor(((min)[1]+(w)->gridbias[1]) / (w)->gridscale[1]); \
|
||||
maxg[0] = floor(((max)[0]+(w)->gridbias[0]) / (w)->gridscale[0]); \
|
||||
maxg[1] = floor(((max)[1]+(w)->gridbias[1]) / (w)->gridscale[1]); \
|
||||
ming[0] = bound(0, ming[0], (w)->gridsize[0]-1); \
|
||||
ming[1] = bound(0, ming[1], (w)->gridsize[1]-1); \
|
||||
maxg[0] = bound(ming[0], maxg[0], (w)->gridsize[0]-1)+1; \
|
||||
maxg[1] = bound(ming[1], maxg[1], (w)->gridsize[1]-1)+1;
|
||||
#else
|
||||
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,wedict_t,area)
|
||||
#endif
|
||||
|
||||
#if defined(Q2SERVER) || !defined(USEAREAGRID)
|
||||
//q2 game code embeds a link_t struct inside the public edicts.
|
||||
//this is why we can't have nice things.
|
||||
|
||||
//a binary tree. ents straddling a node are inserted into the parent.
|
||||
//this is a problem when your root note passes through '0 0 0' and you have shitty mods with 2000 such ents.
|
||||
typedef struct areanode_s
|
||||
{
|
||||
int axis; // -1 = leaf node
|
||||
|
@ -139,8 +161,7 @@ typedef struct areanode_s
|
|||
struct areanode_s *children[2];
|
||||
link_t edicts;
|
||||
} areanode_t;
|
||||
|
||||
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,wedict_t,area)
|
||||
#endif
|
||||
|
||||
typedef struct wedict_s wedict_t;
|
||||
#define PROG_TO_WEDICT (wedict_t*)PROG_TO_EDICT
|
||||
|
@ -189,10 +210,23 @@ struct world_s
|
|||
struct pubprogfuncs_s *progs;
|
||||
qboolean usesolidcorpse; //to disable SOLID_CORPSE when running hexen2 due to conflict.
|
||||
model_t *worldmodel;
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
vec2_t gridbias;
|
||||
vec2_t gridscale;
|
||||
size_t gridsize[2];
|
||||
areagridlink_t *gridareas; //[gridsize[0]*gridsize[1]]
|
||||
areagridlink_t jumboarea; //node containing ents too large to fit.
|
||||
areagridlink_t portallist;
|
||||
#else
|
||||
areanode_t portallist;
|
||||
#endif
|
||||
|
||||
#if defined(Q2SERVER) || !defined(USEAREAGRID)
|
||||
areanode_t *areanodes;
|
||||
int areanodedepth;
|
||||
int numareanodes;
|
||||
areanode_t portallist;
|
||||
#endif
|
||||
|
||||
double physicstime; // the last time global physics were run
|
||||
unsigned int framenum;
|
||||
|
@ -263,6 +297,7 @@ void World_RBE_Shutdown(world_t *world);
|
|||
|
||||
void World_ClearWorld (world_t *w, qboolean relink);
|
||||
// called after the world model has been loaded, before linking any entities
|
||||
void World_ClearWorld_Nodes (world_t *w, qboolean relink); //legacy code for q2 compat.
|
||||
|
||||
void World_UnlinkEdict (wedict_t *ent);
|
||||
// call before removing an entity, and before trying to move one,
|
||||
|
@ -275,7 +310,13 @@ void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers);
|
|||
// sets ent->v.absmin and ent->v.absmax
|
||||
// if touchtriggers, calls prog functions for the intersected triggers
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
void World_TouchAllLinks (world_t *w, wedict_t *ent);
|
||||
extern size_t areagridsequence;
|
||||
#else
|
||||
void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node);
|
||||
#define World_TouchAllLinks(w,e) World_TouchLinks(w,e,(w)->areanodes)
|
||||
#endif
|
||||
|
||||
int World_PointContents (world_t *w, vec3_t p);
|
||||
// returns the CONTENTS_* value from the world at the given point.
|
||||
|
|
|
@ -161,6 +161,8 @@ typedef struct
|
|||
vec4_t e_lmscale[4];
|
||||
vec4_t e_uppercolour;
|
||||
vec4_t e_lowercolour;
|
||||
vec4_t e_colourmod;
|
||||
vec4_t e_glowmod;
|
||||
} cbuf_entity_t;
|
||||
|
||||
//vertex attributes
|
||||
|
@ -250,6 +252,7 @@ typedef struct
|
|||
ID3D11Buffer *stream_buffer[D3D11_BUFF_MAX];
|
||||
unsigned int stream_stride[D3D11_BUFF_MAX];
|
||||
unsigned int stream_offset[D3D11_BUFF_MAX];
|
||||
qboolean stream_rgbaf;
|
||||
|
||||
program_t *programfixedemu[4];
|
||||
|
||||
|
@ -1056,6 +1059,12 @@ static void SelectPassTexture(unsigned int tu, const shaderpass_t *pass)
|
|||
case T_GEN_FULLBRIGHT:
|
||||
BindTexture(tu, shaderstate.curtexnums->fullbright);
|
||||
break;
|
||||
case T_GEN_REFLECTCUBE:
|
||||
BindTexture(tu, shaderstate.curtexnums->reflectcube);
|
||||
break;
|
||||
case T_GEN_REFLECTMASK:
|
||||
BindTexture(tu, shaderstate.curtexnums->reflectmask);
|
||||
break;
|
||||
case T_GEN_ANIMMAP:
|
||||
BindTexture(tu, pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes]);
|
||||
break;
|
||||
|
@ -1414,6 +1423,7 @@ static void BE_GenerateColourMods(unsigned int vertcount, const shaderpass_t *pa
|
|||
const mesh_t *m = shaderstate.meshlist[0];
|
||||
if (pass->flags & SHADER_PASS_NOCOLORARRAY)
|
||||
{
|
||||
#if 1
|
||||
ID3D11Buffer *buf;
|
||||
unsigned char *map;
|
||||
unsigned int offset;
|
||||
|
@ -1429,6 +1439,25 @@ static void BE_GenerateColourMods(unsigned int vertcount, const shaderpass_t *pa
|
|||
shaderstate.stream_buffer[D3D11_BUFF_COL] = buf;
|
||||
shaderstate.stream_offset[D3D11_BUFF_COL] = offset;
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = 0; //omg that's so lame!
|
||||
shaderstate.stream_rgbaf = false;
|
||||
#else
|
||||
ID3D11Buffer *buf;
|
||||
unsigned char *map;
|
||||
unsigned int offset;
|
||||
vec4_t passcolour;
|
||||
static vec4_t fakesource = {1,1,1,1};
|
||||
allocvertexbuffer(&buf, &offset, (void**)&map, sizeof(fakesource));
|
||||
|
||||
colourgen(pass, 1, (vec4_t*)&fakesource, NULL, (vec4_t*)&passcolour, m);
|
||||
alphagen(pass, 1, (vec4_t*)&fakesource, NULL, (vec4_t*)&passcolour, m);
|
||||
Vector4Copy(passcolour, map);
|
||||
|
||||
ID3D11DeviceContext_Unmap(d3ddevctx, (ID3D11Resource*)buf, 0);
|
||||
shaderstate.stream_buffer[D3D11_BUFF_COL] = buf;
|
||||
shaderstate.stream_offset[D3D11_BUFF_COL] = offset;
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = 0; //omg that's so lame!
|
||||
shaderstate.stream_rgbaf = true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1441,6 +1470,7 @@ static void BE_GenerateColourMods(unsigned int vertcount, const shaderpass_t *pa
|
|||
shaderstate.stream_buffer[D3D11_BUFF_COL] = shaderstate.batchvbo->colours[0].d3d.buff;
|
||||
shaderstate.stream_offset[D3D11_BUFF_COL] = shaderstate.batchvbo->colours[0].d3d.offs;
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(vbovdata_t);
|
||||
shaderstate.stream_rgbaf = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1460,6 +1490,7 @@ static void BE_GenerateColourMods(unsigned int vertcount, const shaderpass_t *pa
|
|||
shaderstate.stream_buffer[D3D11_BUFF_COL] = buf;
|
||||
shaderstate.stream_offset[D3D11_BUFF_COL] = offset;
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(byte_vec4_t);
|
||||
shaderstate.stream_rgbaf = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1888,7 +1919,7 @@ static void BE_ApplyUniforms(program_t *prog, int permu)
|
|||
shaderstate.lcbuffer //light buffer that changes rarelyish
|
||||
};
|
||||
//FIXME: how many of these calls can we avoid?
|
||||
ID3D11DeviceContext_IASetInputLayout(d3ddevctx, prog->permu[permu].h.hlsl.layout);
|
||||
ID3D11DeviceContext_IASetInputLayout(d3ddevctx, prog->permu[permu].h.hlsl.layouts[shaderstate.stream_rgbaf]);
|
||||
ID3D11DeviceContext_VSSetShader(d3ddevctx, prog->permu[permu].h.hlsl.vert, NULL, 0);
|
||||
ID3D11DeviceContext_HSSetShader(d3ddevctx, prog->permu[permu].h.hlsl.hull, NULL, 0);
|
||||
ID3D11DeviceContext_DSSetShader(d3ddevctx, prog->permu[permu].h.hlsl.domain, NULL, 0);
|
||||
|
@ -2230,6 +2261,7 @@ static void BE_DrawMeshChain_Internal(void)
|
|||
shaderstate.stream_buffer[D3D11_BUFF_COL] = shaderstate.batchvbo->colours[0].d3d.buff;
|
||||
shaderstate.stream_offset[D3D11_BUFF_COL] = shaderstate.batchvbo->colours[0].d3d.offs;
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(vbovdata_t);
|
||||
shaderstate.stream_rgbaf = false;
|
||||
shaderstate.stream_buffer[D3D11_BUFF_TC] = shaderstate.batchvbo->texcoord.d3d.buff;
|
||||
shaderstate.stream_offset[D3D11_BUFF_TC] = shaderstate.batchvbo->texcoord.d3d.offs;
|
||||
shaderstate.stream_stride[D3D11_BUFF_TC] = sizeof(vbovdata_t);
|
||||
|
@ -2251,19 +2283,19 @@ static void BE_DrawMeshChain_Internal(void)
|
|||
|
||||
if (shaderstate.meshlist[0]->colors4f_array[0])
|
||||
{
|
||||
byte_vec4_t *map;
|
||||
allocvertexbuffer(&buf, &offset, (void**)&map, vertcount*sizeof(byte_vec4_t));
|
||||
vec4_t *map;
|
||||
allocvertexbuffer(&buf, &offset, (void**)&map, vertcount*sizeof(*map));
|
||||
for (mno = 0; mno < shaderstate.nummeshes; mno++)
|
||||
{
|
||||
m = shaderstate.meshlist[mno];
|
||||
for (i = 0; i < m->numvertexes; i++)
|
||||
((int*)map)[i] = D3DCOLOR_COLORVALUE(m->colors4f_array[0][i][2], m->colors4f_array[0][i][1], m->colors4f_array[0][i][0], m->colors4f_array[0][i][3]);
|
||||
memcpy(map, m->colors4f_array[0], sizeof(*map)*m->numvertexes);
|
||||
map += m->numvertexes;
|
||||
}
|
||||
ID3D11DeviceContext_Unmap(d3ddevctx, (ID3D11Resource*)buf, 0);
|
||||
shaderstate.stream_buffer[D3D11_BUFF_COL] = buf;
|
||||
shaderstate.stream_offset[D3D11_BUFF_COL] = offset;
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(byte_vec4_t);
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(*map);
|
||||
shaderstate.stream_rgbaf = true;
|
||||
}
|
||||
else if (shaderstate.meshlist[0]->colors4b_array)
|
||||
{
|
||||
|
@ -2280,12 +2312,14 @@ static void BE_DrawMeshChain_Internal(void)
|
|||
shaderstate.stream_buffer[D3D11_BUFF_COL] = buf;
|
||||
shaderstate.stream_offset[D3D11_BUFF_COL] = offset;
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = sizeof(byte_vec4_t);
|
||||
shaderstate.stream_rgbaf = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
shaderstate.stream_buffer[D3D11_BUFF_COL] = 0;
|
||||
shaderstate.stream_offset[D3D11_BUFF_COL] = 0;
|
||||
shaderstate.stream_stride[D3D11_BUFF_COL] = 0;
|
||||
shaderstate.stream_rgbaf = false;
|
||||
}
|
||||
|
||||
if (shaderstate.meshlist[0]->lmst_array[0])
|
||||
|
@ -2669,7 +2703,7 @@ static void BE_UploadLightmaps(qboolean force)
|
|||
if (!lightmap[i])
|
||||
continue;
|
||||
|
||||
if (force)
|
||||
if (force && !lightmap[i]->external)
|
||||
{
|
||||
lightmap[i]->rectchange.l = 0;
|
||||
lightmap[i]->rectchange.t = 0;
|
||||
|
@ -3001,6 +3035,9 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod)
|
|||
|
||||
R_FetchPlayerColour(e->topcolour, cbe->e_uppercolour);
|
||||
R_FetchPlayerColour(e->bottomcolour, cbe->e_lowercolour);
|
||||
R_FetchPlayerColour(e->bottomcolour, cbe->e_colourmod);
|
||||
VectorCopy(e->shaderRGBAf, cbe->e_colourmod);
|
||||
VectorCopy(e->glowmod, cbe->e_glowmod);cbe->e_glowmod[3] = 1;
|
||||
|
||||
//various stuff in modelspace
|
||||
Matrix4x4_CM_Transform3(modelinv, r_origin, cbe->e_eyepos);
|
||||
|
@ -3138,12 +3175,13 @@ static void BE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
|
||||
if (batch->shader->flags & SHADER_SKY)
|
||||
{
|
||||
if (!batch->shader->prog)
|
||||
if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK)
|
||||
{
|
||||
if (shaderstate.mode == BEM_STANDARD)
|
||||
R_DrawSkyChain (batch);
|
||||
if (R_DrawSkyChain (batch))
|
||||
continue;
|
||||
}
|
||||
else if (shaderstate.mode != BEM_FOG && shaderstate.mode != BEM_CREPUSCULAR && shaderstate.mode != BEM_WIREFRAME)
|
||||
continue;
|
||||
}
|
||||
|
||||
BE_SubmitBatch(batch);
|
||||
|
@ -3611,7 +3649,7 @@ void D3D11BE_DrawWorld (batch_t **worldbatches)
|
|||
shaderstate.identitylighting = r_shadow_realtime_world_lightmaps.value;
|
||||
else
|
||||
#endif
|
||||
shaderstate.identitylighting = 1;
|
||||
shaderstate.identitylighting = r_lightmap_scale.value;
|
||||
shaderstate.identitylighting *= r_refdef.hdr_value;
|
||||
// shaderstate.identitylightmap = shaderstate.identitylighting / (1<<gl_overbright.ival);
|
||||
|
||||
|
@ -3619,23 +3657,25 @@ void D3D11BE_DrawWorld (batch_t **worldbatches)
|
|||
|
||||
RSpeedRemark();
|
||||
D3D11BE_SubmitMeshes(worldbatches, batches, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1);
|
||||
RSpeedEnd(RSPEED_WORLD);
|
||||
RSpeedEnd(RSPEED_OPAQUE);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
RSpeedRemark();
|
||||
D3D11BE_SelectEntity(&r_worldentity);
|
||||
Sh_DrawLights(r_refdef.scenevis);
|
||||
RSpeedEnd(RSPEED_STENCILSHADOWS);
|
||||
RSpeedEnd(RSPEED_RTLIGHTS);
|
||||
#endif
|
||||
|
||||
RSpeedRemark();
|
||||
D3D11BE_SubmitMeshes(worldbatches, batches, SHADER_SORT_SEETHROUGH+1, SHADER_SORT_COUNT);
|
||||
RSpeedEnd(RSPEED_TRANSPARENTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
RSpeedRemark();
|
||||
shaderstate.identitylighting = 1;
|
||||
D3D11BE_SubmitMeshes(NULL, batches, SHADER_SORT_PORTAL, SHADER_SORT_COUNT);
|
||||
RSpeedEnd(RSPEED_DRAWENTITIES);
|
||||
RSpeedEnd(RSPEED_OPAQUE);
|
||||
}
|
||||
|
||||
R_RenderDlights ();
|
||||
|
|
|
@ -155,6 +155,8 @@ HRESULT STDMETHODCALLTYPE d3dinclude_Open(ID3DInclude *this, D3D_INCLUDE_TYPE In
|
|||
"float4 e_lmscale[4];\n"
|
||||
"float4 e_uppercolour;\n"
|
||||
"float4 e_lowercolour;\n"
|
||||
"float4 e_colourmod;\n"
|
||||
"float4 e_glowmod;\n"
|
||||
"};\n"
|
||||
"cbuffer fteviewdefs : register(b1)\n"
|
||||
"{\n"
|
||||
|
@ -208,20 +210,23 @@ void D3D11Shader_DeleteProg(program_t *prog)
|
|||
ID3D11InputLayout *layout;
|
||||
ID3D11PixelShader *frag;
|
||||
ID3D11VertexShader *vert;
|
||||
unsigned int permu;
|
||||
unsigned int permu, l;
|
||||
for (permu = 0; permu < countof(prog->permu); permu++)
|
||||
{
|
||||
vert = prog->permu[permu].h.hlsl.vert;
|
||||
frag = prog->permu[permu].h.hlsl.frag;
|
||||
layout = prog->permu[permu].h.hlsl.layout;
|
||||
if (vert)
|
||||
ID3D11VertexShader_Release(vert);
|
||||
if (frag)
|
||||
ID3D11PixelShader_Release(frag);
|
||||
for (l = 0; l < countof(prog->permu[permu].h.hlsl.layouts); l++)
|
||||
{
|
||||
layout = prog->permu[permu].h.hlsl.layouts[l];
|
||||
if (layout)
|
||||
ID3D11InputLayout_Release(layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//create a program from two blobs.
|
||||
static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int permu,
|
||||
|
@ -231,6 +236,7 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int
|
|||
void *gblob, size_t gsize,
|
||||
void *fblob, size_t fsize)
|
||||
{
|
||||
int l;
|
||||
qboolean success = true;
|
||||
|
||||
if (FAILED(ID3D11Device_CreateVertexShader(pD3DDev11, vblob, vsize, NULL, (ID3D11VertexShader**)&prog->permu[permu].h.hlsl.vert)))
|
||||
|
@ -254,7 +260,7 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int
|
|||
if (FAILED(ID3D11Device_CreatePixelShader(pD3DDev11, fblob, fsize, NULL, (ID3D11PixelShader**)&prog->permu[permu].h.hlsl.frag)))
|
||||
success = false;
|
||||
|
||||
if (success)
|
||||
for (l = 0; l < 2 && success; l++)
|
||||
{
|
||||
D3D11_INPUT_ELEMENT_DESC decl[13];
|
||||
int elements = 0;
|
||||
|
@ -288,7 +294,7 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int
|
|||
|
||||
decl[elements].SemanticName = "COLOR";
|
||||
decl[elements].SemanticIndex = 0;
|
||||
decl[elements].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
decl[elements].Format = l?DXGI_FORMAT_R32G32B32A32_FLOAT:DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
decl[elements].InputSlot = D3D11_BUFF_COL;
|
||||
decl[elements].AlignedByteOffset = 0;
|
||||
decl[elements].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
|
@ -341,7 +347,7 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int
|
|||
decl[elements].InstanceDataStepRate = 0;
|
||||
elements++;
|
||||
*/
|
||||
if (FAILED(ID3D11Device_CreateInputLayout(pD3DDev11, decl, elements, vblob, vsize, (ID3D11InputLayout**)&prog->permu[permu].h.hlsl.layout)))
|
||||
if (FAILED(ID3D11Device_CreateInputLayout(pD3DDev11, decl, elements, vblob, vsize, (ID3D11InputLayout**)&prog->permu[permu].h.hlsl.layouts[l])))
|
||||
{
|
||||
Con_Printf("HLSL Shader %s requires unsupported inputs\n", name);
|
||||
success = false;
|
||||
|
@ -450,7 +456,7 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
|
|||
prog->permu[permu].h.hlsl.hull = NULL;
|
||||
prog->permu[permu].h.hlsl.domain = NULL;
|
||||
prog->permu[permu].h.hlsl.geom = NULL;
|
||||
prog->permu[permu].h.hlsl.layout = NULL;
|
||||
memset(prog->permu[permu].h.hlsl.layouts, 0, sizeof(prog->permu[permu].h.hlsl.layouts));
|
||||
|
||||
if (pD3DCompile)
|
||||
{
|
||||
|
@ -732,6 +738,7 @@ qboolean D3D11Shader_Init(unsigned int flevel)
|
|||
sh_config.pProgAutoFields = NULL;
|
||||
|
||||
sh_config.can_mipcap = true; //at creation time
|
||||
sh_config.havecubemaps = true;
|
||||
|
||||
// sh_config.tex_env_combine = 1;
|
||||
// sh_config.nv_tex_env_combine4 = 1;
|
||||
|
|
|
@ -3371,7 +3371,7 @@ void D3D8BE_DrawWorld (batch_t **worldbatches)
|
|||
shaderstate_identitylighting = r_shadow_realtime_world_lightmaps.value;
|
||||
else
|
||||
#endif
|
||||
shaderstate_identitylighting = 1;
|
||||
shaderstate_identitylighting = r_lightmap_scale.value;
|
||||
shaderstate_identitylighting *= r_refdef.hdr_value;
|
||||
// shaderstate_identitylightmap = shaderstate.identitylighting / (1<<gl_overbright.ival);
|
||||
|
||||
|
@ -3382,7 +3382,7 @@ void D3D8BE_DrawWorld (batch_t **worldbatches)
|
|||
|
||||
RSpeedRemark();
|
||||
D3D8BE_SubmitMeshes(worldbatches, batches, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1);
|
||||
RSpeedEnd(RSPEED_WORLD);
|
||||
RSpeedEnd(RSPEED_OPAQUE);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
if (r_refdef.scenevis)
|
||||
|
@ -3390,19 +3390,21 @@ void D3D8BE_DrawWorld (batch_t **worldbatches)
|
|||
RSpeedRemark();
|
||||
D3D8BE_SelectEntity(&r_worldentity);
|
||||
Sh_DrawLights(r_refdef.scenevis);
|
||||
RSpeedEnd(RSPEED_STENCILSHADOWS);
|
||||
RSpeedEnd(RSPEED_RTLIGHTS);
|
||||
}
|
||||
#endif
|
||||
|
||||
BE_SelectMode(BEM_STANDARD);
|
||||
|
||||
RSpeedRemark();
|
||||
D3D8BE_SubmitMeshes(worldbatches, batches, SHADER_SORT_SEETHROUGH+1, SHADER_SORT_COUNT);
|
||||
RSpeedEnd(RSPEED_TRANSPARENTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
RSpeedRemark();
|
||||
D3D8BE_SubmitMeshes(NULL, batches, SHADER_SORT_PORTAL, SHADER_SORT_COUNT);
|
||||
RSpeedEnd(RSPEED_DRAWENTITIES);
|
||||
RSpeedEnd(RSPEED_OPAQUE);
|
||||
}
|
||||
|
||||
R_RenderDlights ();
|
||||
|
|
|
@ -765,6 +765,12 @@ static void SelectPassTexture(unsigned int tu, shaderpass_t *pass)
|
|||
case T_GEN_FULLBRIGHT:
|
||||
BindTexture(tu, shaderstate.curtexnums->fullbright);
|
||||
break;
|
||||
case T_GEN_REFLECTCUBE:
|
||||
BindTexture(tu, shaderstate.curtexnums->reflectcube);
|
||||
break;
|
||||
case T_GEN_REFLECTMASK:
|
||||
BindTexture(tu, shaderstate.curtexnums->reflectmask);
|
||||
break;
|
||||
case T_GEN_ANIMMAP:
|
||||
BindTexture(tu, pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes]);
|
||||
break;
|
||||
|
@ -3146,12 +3152,13 @@ static void BE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
|
||||
if (batch->shader->flags & SHADER_SKY)
|
||||
{
|
||||
if (!batch->shader->prog)
|
||||
if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK)
|
||||
{
|
||||
if (shaderstate.mode == BEM_STANDARD)
|
||||
R_DrawSkyChain (batch);
|
||||
if (R_DrawSkyChain (batch))
|
||||
continue;
|
||||
}
|
||||
else if (shaderstate.mode != BEM_FOG && shaderstate.mode != BEM_CREPUSCULAR && shaderstate.mode != BEM_WIREFRAME)
|
||||
continue;
|
||||
}
|
||||
|
||||
BE_SubmitBatch(batch);
|
||||
|
@ -3546,7 +3553,7 @@ void D3D9BE_DrawWorld (batch_t **worldbatches)
|
|||
shaderstate_identitylighting = r_shadow_realtime_world_lightmaps.value;
|
||||
else
|
||||
#endif
|
||||
shaderstate_identitylighting = 1;
|
||||
shaderstate_identitylighting = r_lightmap_scale.value;
|
||||
shaderstate_identitylighting *= r_refdef.hdr_value;
|
||||
// shaderstate_identitylightmap = shaderstate.identitylighting / (1<<gl_overbright.ival);
|
||||
|
||||
|
@ -3557,7 +3564,7 @@ void D3D9BE_DrawWorld (batch_t **worldbatches)
|
|||
|
||||
RSpeedRemark();
|
||||
D3D9BE_SubmitMeshes(worldbatches, batches, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1);
|
||||
RSpeedEnd(RSPEED_WORLD);
|
||||
RSpeedEnd(RSPEED_OPAQUE);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
if (r_refdef.scenevis)
|
||||
|
@ -3565,19 +3572,21 @@ void D3D9BE_DrawWorld (batch_t **worldbatches)
|
|||
RSpeedRemark();
|
||||
D3D9BE_SelectEntity(&r_worldentity);
|
||||
Sh_DrawLights(r_refdef.scenevis);
|
||||
RSpeedEnd(RSPEED_STENCILSHADOWS);
|
||||
RSpeedEnd(RSPEED_RTLIGHTS);
|
||||
}
|
||||
#endif
|
||||
|
||||
BE_SelectMode(BEM_STANDARD);
|
||||
|
||||
RSpeedRemark();
|
||||
D3D9BE_SubmitMeshes(worldbatches, batches, SHADER_SORT_SEETHROUGH+1, SHADER_SORT_COUNT);
|
||||
RSpeedEnd(RSPEED_TRANSPARENTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
RSpeedRemark();
|
||||
D3D9BE_SubmitMeshes(NULL, batches, SHADER_SORT_PORTAL, SHADER_SORT_COUNT);
|
||||
RSpeedEnd(RSPEED_DRAWENTITIES);
|
||||
RSpeedEnd(RSPEED_OPAQUE);
|
||||
}
|
||||
|
||||
R_RenderDlights ();
|
||||
|
|
|
@ -14,7 +14,7 @@ void D3D9_DestroyTexture (texid_t tex)
|
|||
return;
|
||||
|
||||
if (tex->ptr)
|
||||
IDirect3DTexture9_Release((IDirect3DTexture9*)tex->ptr);
|
||||
IDirect3DBaseTexture9_Release((IDirect3DBaseTexture9*)tex->ptr);
|
||||
tex->ptr = NULL;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip
|
|||
D3DLOCKED_RECT lock;
|
||||
D3DFORMAT fmt;
|
||||
D3DSURFACE_DESC desc;
|
||||
IDirect3DTexture9 *dt;
|
||||
IDirect3DBaseTexture9 *dbt;
|
||||
qboolean swap = false;
|
||||
unsigned int pixelsize = 4;
|
||||
unsigned int blocksize = 0;
|
||||
|
@ -90,8 +90,60 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip
|
|||
|
||||
if (!pD3DDev9)
|
||||
return false; //can happen on errors
|
||||
if (mips->type == PTI_CUBEMAP)
|
||||
{
|
||||
IDirect3DCubeTexture9 *dt;
|
||||
if (FAILED(IDirect3DDevice9_CreateCubeTexture(pD3DDev9, mips->mip[0].width, mips->mipcount/6, 0, fmt, D3DPOOL_MANAGED, &dt, NULL)))
|
||||
return false;
|
||||
dbt = (IDirect3DBaseTexture9*)dt;
|
||||
|
||||
for (i = 0; i < mips->mipcount; i++)
|
||||
{
|
||||
IDirect3DCubeTexture9_GetLevelDesc(dt, i/6, &desc);
|
||||
|
||||
if (mips->mip[i].height != desc.Height || mips->mip[i].width != desc.Width)
|
||||
{
|
||||
IDirect3DCubeTexture9_Release(dt);
|
||||
return false;
|
||||
}
|
||||
|
||||
IDirect3DCubeTexture9_LockRect(dt, i%6, i/6, &lock, NULL, D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD);
|
||||
//can't do it in one go. pitch might contain padding or be upside down.
|
||||
if (!mips->mip[i].data)
|
||||
;
|
||||
else if (blocksize)
|
||||
{
|
||||
if (lock.Pitch == ((mips->mip[i].width+3)/4)*blocksize)
|
||||
//for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize)
|
||||
memcpy(lock.pBits, mips->mip[i].data, mips->mip[i].datasize);
|
||||
}
|
||||
else if (swap)
|
||||
{
|
||||
for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*4)
|
||||
{
|
||||
for (x = 0; x < mips->mip[i].width*4; x+=4)
|
||||
{
|
||||
out[x+0] = in[x+2];
|
||||
out[x+1] = in[x+1];
|
||||
out[x+2] = in[x+0];
|
||||
out[x+3] = in[x+3];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize)
|
||||
memcpy(out, in, mips->mip[i].width*pixelsize);
|
||||
}
|
||||
IDirect3DCubeTexture9_UnlockRect(dt, i%6, i/6);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IDirect3DTexture9 *dt;
|
||||
if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mips->mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL)))
|
||||
return false;
|
||||
dbt = (IDirect3DBaseTexture9*)dt;
|
||||
|
||||
for (i = 0; i < mips->mipcount; i++)
|
||||
{
|
||||
|
@ -133,9 +185,9 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip
|
|||
}
|
||||
IDirect3DTexture9_UnlockRect(dt, i);
|
||||
}
|
||||
|
||||
}
|
||||
D3D9_DestroyTexture(tex);
|
||||
tex->ptr = dt;
|
||||
tex->ptr = dbt;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -474,6 +474,7 @@ void D3D9Shader_Init(void)
|
|||
sh_config.env_add = 1;
|
||||
|
||||
sh_config.can_mipcap = true; //at creation time, I think.
|
||||
sh_config.havecubemaps = true;
|
||||
|
||||
IDirect3DDevice9_GetDeviceCaps(pD3DDev9, &caps);
|
||||
|
||||
|
|
|
@ -576,7 +576,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
|
|||
skinfile_t *sk = Mod_LookupSkin(e->customskin);
|
||||
if (sk)
|
||||
{
|
||||
int i;
|
||||
int i, fallback=-1;
|
||||
if (inf->geomset < MAX_GEOMSETS && sk->geomset[inf->geomset] != inf->geomid)
|
||||
return NULL; //don't allow this surface to be drawn.
|
||||
for (i = 0; i < sk->nummappings; i++)
|
||||
|
@ -586,6 +586,13 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
|
|||
*forcedtex = &sk->mappings[i].texnums;
|
||||
return sk->mappings[i].shader;
|
||||
}
|
||||
if (!*sk->mappings[i].surface)
|
||||
fallback = i;
|
||||
}
|
||||
if (fallback >= 0)
|
||||
{
|
||||
*forcedtex = &sk->mappings[fallback].texnums;
|
||||
return sk->mappings[fallback].shader;
|
||||
}
|
||||
if (!sk->qwskin && *sk->qwskinname)
|
||||
sk->qwskin = Skin_Lookup(sk->qwskinname);
|
||||
|
|
|
@ -1194,7 +1194,12 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
|
|||
GL_LazyBind(tmu, GL_TEXTURE_CUBE_MAP_ARB, t);
|
||||
return;
|
||||
case T_GEN_REFLECTMASK:
|
||||
if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->reflectmask))
|
||||
t = shaderstate.curtexnums->reflectmask;
|
||||
else if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->base))
|
||||
t = shaderstate.curtexnums->base;
|
||||
else
|
||||
t = r_whiteimage;
|
||||
break;
|
||||
case T_GEN_SHADOWMAP:
|
||||
t = shaderstate.curshadowmap;
|
||||
|
@ -1649,6 +1654,28 @@ static void GenerateTCFog(int passnum, mfog_t *fog)
|
|||
}
|
||||
#endif
|
||||
|
||||
static float *tcgen3(const shaderpass_t *pass, int cnt, float *dst, const mesh_t *mesh)
|
||||
{
|
||||
int i;
|
||||
vecV_t *src;
|
||||
switch (pass->tcgen)
|
||||
{
|
||||
default:
|
||||
case TC_GEN_SKYBOX:
|
||||
src = mesh->xyz_array;
|
||||
for (i = 0; i < cnt; i++, dst += 3)
|
||||
{
|
||||
dst[0] = src[i][0] - r_refdef.vieworg[0];
|
||||
dst[1] = r_refdef.vieworg[1] - src[i][1];
|
||||
dst[2] = src[i][2] - r_refdef.vieworg[2];
|
||||
}
|
||||
return dst-cnt*3;
|
||||
|
||||
// case TC_GEN_WOBBLESKY:
|
||||
// case TC_GEN_REFLECT:
|
||||
// break;
|
||||
}
|
||||
}
|
||||
static float *tcgen(const shaderpass_t *pass, int cnt, float *dst, const mesh_t *mesh)
|
||||
{
|
||||
int i;
|
||||
|
@ -1684,7 +1711,7 @@ static float *tcgen(const shaderpass_t *pass, int cnt, float *dst, const mesh_t
|
|||
dst[0] = DotProduct(pass->tcgenvec[0], src[i]);
|
||||
dst[1] = DotProduct(pass->tcgenvec[1], src[i]);
|
||||
}
|
||||
return dst;
|
||||
return dst-cnt*2;
|
||||
|
||||
// case TC_GEN_SKYBOX:
|
||||
// case TC_GEN_WOBBLESKY:
|
||||
|
@ -1772,11 +1799,75 @@ static void tcmod(const tcmod_t *tcmod, int cnt, const float *src, float *dst, c
|
|||
}
|
||||
break;
|
||||
|
||||
case SHADER_TCMOD_PAGE:
|
||||
{ //simple atlas bias with no scaling. use a separate tcmod for that.
|
||||
int w = tcmod->args[0];
|
||||
int h = tcmod->args[1];
|
||||
float f = shaderstate.curtime / (tcmod->args[2]*w*h);
|
||||
int idx = (f - floor(f))*w*h;
|
||||
t1 = (idx%w)/tcmod->args[0];
|
||||
t2 = (idx/w)/tcmod->args[1];
|
||||
|
||||
for (j = 0; j < cnt; j++, dst += 2, src+=2)
|
||||
{
|
||||
dst[0] = src[0] + t1;
|
||||
dst[1] = src[1] + t2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void GenerateTCMods3(const shaderpass_t *pass, int passnum)
|
||||
{
|
||||
#if 1
|
||||
int m;
|
||||
float *src;
|
||||
mesh_t *mesh;
|
||||
for (m = 0; m < shaderstate.meshcount; m++)
|
||||
{
|
||||
mesh = shaderstate.meshes[m];
|
||||
|
||||
src = tcgen3(pass, mesh->numvertexes, texcoordarray[passnum]+mesh->vbofirstvert*3, mesh);
|
||||
|
||||
if (src != texcoordarray[passnum]+mesh->vbofirstvert*3)
|
||||
{
|
||||
//this shouldn't actually ever be true
|
||||
memcpy(texcoordarray[passnum]+mesh->vbofirstvert*3, src, 8*mesh->numvertexes);
|
||||
}
|
||||
}
|
||||
shaderstate.pendingtexcoordparts[passnum] = 3;
|
||||
shaderstate.pendingtexcoordvbo[passnum] = 0;
|
||||
shaderstate.pendingtexcoordpointer[passnum] = texcoordarray[passnum];
|
||||
#else
|
||||
GL_DeselectVAO();
|
||||
if (!shaderstate.vbo_texcoords[passnum])
|
||||
{
|
||||
shaderstate.vbo_texcoords[passnum] = 0;
|
||||
qglGenBuffersARB(1, &shaderstate.vbo_texcoords[passnum]);
|
||||
}
|
||||
GL_SelectVBO(shaderstate.vbo_texcoords[passnum]);
|
||||
|
||||
{
|
||||
qglBufferDataARB(GL_ARRAY_BUFFER_ARB, MAX_ARRAY_VERTS*sizeof(float)*3, NULL, GL_STREAM_DRAW_ARB);
|
||||
for (; meshlist; meshlist = meshlist->next)
|
||||
{
|
||||
int i;
|
||||
float *src;
|
||||
src = tcge3n(pass, meshlist->numvertexes, texcoordarray[passnum], meshlist);
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, meshlist->vbofirstvert*8, meshlist->numvertexes*8, src);
|
||||
}
|
||||
}
|
||||
|
||||
shaderstate.pendingtexcoordparts[passnum] = 2;
|
||||
shaderstate.pendingtexcoordvbo[passnum] = shaderstate.vbo_texcoords[passnum];
|
||||
shaderstate.pendingtexcoordpointer[passnum] = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void GenerateTCMods(const shaderpass_t *pass, int passnum)
|
||||
{
|
||||
#if 1
|
||||
|
@ -2565,7 +2656,9 @@ static void BE_GeneratePassTC(const shaderpass_t *pass, int tmu)
|
|||
shaderstate.pendingtexcoordvbo[tmu] = shaderstate.sourcevbo->tvector.gl.vbo;
|
||||
shaderstate.pendingtexcoordpointer[tmu] = shaderstate.sourcevbo->tvector.gl.addr;
|
||||
break;
|
||||
// case TC_GEN_SKYBOX:
|
||||
case TC_GEN_SKYBOX:
|
||||
GenerateTCMods3(pass, tmu);
|
||||
break;
|
||||
//position - viewpos
|
||||
// case TC_GEN_WOBBLESKY:
|
||||
// case TC_GEN_REFLECT:
|
||||
|
@ -4674,6 +4767,7 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
|
|||
{
|
||||
batch_t *batch, *masklists[2];
|
||||
int i;
|
||||
float il;
|
||||
|
||||
if (!dynamiclist && !worldlist[SHADER_SORT_PORTAL])
|
||||
return; //no portals to draw
|
||||
|
@ -4691,9 +4785,11 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
|
|||
if (batch->buildmeshes)
|
||||
batch->buildmeshes(batch);
|
||||
|
||||
il = shaderstate.identitylighting;
|
||||
masklists[0] = worldlist[SHADER_SORT_PORTAL];
|
||||
masklists[1] = dynamiclist;
|
||||
GLR_DrawPortal(batch, worldlist, masklists, 0);
|
||||
shaderstate.identitylighting = il;
|
||||
|
||||
/*clear depth again*/
|
||||
GL_ForceDepthWritable();
|
||||
|
@ -4837,7 +4933,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
}
|
||||
if (bs->flags & (SHADER_HASREFRACT|SHADER_HASREFRACTDEPTH))
|
||||
{
|
||||
if (r_refract_fboival)
|
||||
if (r_refract_fboival || (bs->flags&SHADER_HASPORTAL))
|
||||
{
|
||||
float renderscale = min(1, r_refractreflect_scale.value);
|
||||
vrect_t ovrect = r_refdef.vrect;
|
||||
|
@ -4899,6 +4995,9 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
GL_ForceDepthWritable();
|
||||
qglClearColor(0, 0, 0, 1);
|
||||
qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
if (bs->flags&SHADER_HASPORTAL)
|
||||
GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 0);
|
||||
else
|
||||
GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, ((bs->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme
|
||||
GLBE_FBO_Pop(oldfbo);
|
||||
|
||||
|
@ -5565,11 +5664,14 @@ void GLBE_DrawWorld (batch_t **worldbatches)
|
|||
shaderstate.identitylighting = r_shadow_realtime_world_lightmaps.value;
|
||||
else
|
||||
#endif
|
||||
shaderstate.identitylighting = 1;
|
||||
shaderstate.identitylighting = r_lightmap_scale.value;
|
||||
shaderstate.identitylighting *= r_refdef.hdr_value;
|
||||
shaderstate.identitylightmap = shaderstate.identitylighting;
|
||||
// shaderstate.identitylightmap *= 1<<gl_overbright.ival;
|
||||
|
||||
// if (cl.worldmodel && cl.worldmodel->fromgame == fg_quake3)
|
||||
// shaderstate.identitylighting *= 2;
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
if (r_lightprepass)
|
||||
{
|
||||
|
@ -5585,7 +5687,7 @@ void GLBE_DrawWorld (batch_t **worldbatches)
|
|||
|
||||
RSpeedRemark();
|
||||
GLBE_SubmitMeshes(worldbatches, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1);
|
||||
RSpeedEnd(RSPEED_WORLD);
|
||||
RSpeedEnd(RSPEED_OPAQUE);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
if (worldbatches)
|
||||
|
@ -5594,7 +5696,7 @@ void GLBE_DrawWorld (batch_t **worldbatches)
|
|||
TRACE(("GLBE_DrawWorld: drawing lights\n"));
|
||||
GLBE_SelectEntity(&r_worldentity);
|
||||
Sh_DrawLights(r_refdef.scenevis);
|
||||
RSpeedEnd(RSPEED_STENCILSHADOWS);
|
||||
RSpeedEnd(RSPEED_RTLIGHTS);
|
||||
TRACE(("GLBE_DrawWorld: lights drawn\n"));
|
||||
}
|
||||
#endif
|
||||
|
@ -5602,7 +5704,9 @@ void GLBE_DrawWorld (batch_t **worldbatches)
|
|||
|
||||
shaderstate.identitylighting = 1;
|
||||
|
||||
RSpeedRemark();
|
||||
GLBE_SubmitMeshes(worldbatches, SHADER_SORT_SEETHROUGH+1, SHADER_SORT_NEAREST);
|
||||
RSpeedEnd(RSPEED_TRANSPARENTS);
|
||||
|
||||
/* if (r_refdef.gfog_alpha)
|
||||
{
|
||||
|
|
|
@ -268,6 +268,8 @@ static struct font_s *curfont;
|
|||
static float curfont_scale[2];
|
||||
static qboolean curfont_scaled;
|
||||
|
||||
extern cvar_t r_font_linear;
|
||||
|
||||
|
||||
//^Ue2XX
|
||||
static struct
|
||||
|
@ -359,10 +361,10 @@ void Font_Init(void)
|
|||
|
||||
for (i = 0; i < FONTPLANES; i++)
|
||||
{
|
||||
TEXASSIGN(fontplanes.texnum[i], Image_CreateTexture("***fontplane***", NULL, IF_UIPIC|IF_NEAREST|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA));
|
||||
TEXASSIGN(fontplanes.texnum[i], Image_CreateTexture("***fontplane***", NULL, IF_UIPIC|(r_font_linear.ival?IF_LINEAR:IF_NEAREST)|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA));
|
||||
}
|
||||
|
||||
fontplanes.shader = R_RegisterShader("ftefont", SUF_NONE,
|
||||
fontplanes.shader = R_RegisterShader("ftefont", SUF_2D,
|
||||
"{\n"
|
||||
"if $nofixed\n"
|
||||
"program default2d\n"
|
||||
|
@ -377,7 +379,7 @@ void Font_Init(void)
|
|||
"}\n"
|
||||
);
|
||||
|
||||
fontplanes.backshader = R_RegisterShader("ftefontback", SUF_NONE,
|
||||
fontplanes.backshader = R_RegisterShader("ftefontback", SUF_2D,
|
||||
"{\n"
|
||||
"nomipmaps\n"
|
||||
"{\n"
|
||||
|
@ -498,15 +500,20 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, in
|
|||
int x, y;
|
||||
unsigned char *out;
|
||||
struct charcache_s *c = &f->chars[charidx];
|
||||
int pad = 0;
|
||||
#define BORDERCOLOUR 0
|
||||
|
||||
if (fontplanes.planerowx + (int)bmw >= PLANEWIDTH)
|
||||
if (fontplanes.texnum[0]->flags & IF_LINEAR)
|
||||
pad += 1; //pad the image data to avoid sampling outside
|
||||
|
||||
if (fontplanes.planerowx + (int)bmw+pad*2 >= PLANEWIDTH)
|
||||
{
|
||||
fontplanes.planerowx = 0;
|
||||
fontplanes.planerowy += fontplanes.planerowh;
|
||||
fontplanes.planerowh = 0;
|
||||
}
|
||||
|
||||
if (fontplanes.planerowy+(int)bmh >= PLANEHEIGHT)
|
||||
if (fontplanes.planerowy+(int)bmh+pad*2 >= PLANEHEIGHT)
|
||||
Font_FlushPlane();
|
||||
|
||||
if (fontplanes.newestchar)
|
||||
|
@ -517,41 +524,71 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, in
|
|||
c->nextchar = NULL;
|
||||
|
||||
c->texplane = fontplanes.activeplane;
|
||||
c->bmx = fontplanes.planerowx;
|
||||
c->bmy = fontplanes.planerowy;
|
||||
c->bmx = fontplanes.planerowx+pad;
|
||||
c->bmy = fontplanes.planerowy+pad;
|
||||
c->bmw = bmw;
|
||||
c->bmh = bmh;
|
||||
|
||||
if (fontplanes.planerowh < (int)bmh)
|
||||
fontplanes.planerowh = bmh;
|
||||
fontplanes.planerowx += bmw;
|
||||
if (fontplanes.planerowh < (int)bmh+pad*2)
|
||||
fontplanes.planerowh = bmh+pad*2;
|
||||
fontplanes.planerowx += bmw+pad*2;
|
||||
|
||||
out = (unsigned char *)&fontplanes.plane[c->bmx+(int)c->bmy*PLANEHEIGHT];
|
||||
out = (unsigned char *)&fontplanes.plane[c->bmx+((int)c->bmy-pad)*PLANEHEIGHT];
|
||||
if (alphaonly)
|
||||
{
|
||||
for (y = 0; y < bmh; y++)
|
||||
for (y = -pad; y < 0; y++)
|
||||
{
|
||||
for (x = 0; x < bmw; x++)
|
||||
for (x = -pad; x < bmw+pad; x++)
|
||||
*(unsigned int *)&out[x*4] = BORDERCOLOUR;
|
||||
out += PLANEWIDTH*4;
|
||||
}
|
||||
for (; y < bmh; y++)
|
||||
{
|
||||
for (x = -pad; x < 0; x++)
|
||||
*(unsigned int *)&out[x*4] = BORDERCOLOUR;
|
||||
for (; x < bmw; x++)
|
||||
{
|
||||
*(unsigned int *)&out[x*4] = 0xffffffff;
|
||||
out[x*4+3] = ((unsigned char*)data)[x];
|
||||
}
|
||||
for (; x < bmw+pad; x++)
|
||||
*(unsigned int *)&out[x*4] = BORDERCOLOUR;
|
||||
data = (char*)data + pitch;
|
||||
out += PLANEWIDTH*4;
|
||||
}
|
||||
for (; y < bmh+pad; y++)
|
||||
{
|
||||
for (x = -pad; x < bmw+pad; x++)
|
||||
*(unsigned int *)&out[x*4] = BORDERCOLOUR;
|
||||
out += PLANEWIDTH*4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pitch*=4;
|
||||
for (y = 0; y < bmh; y++)
|
||||
for (y = -pad; y < 0; y++)
|
||||
{
|
||||
for (x = 0; x < bmw; x++)
|
||||
{
|
||||
((unsigned int*)out)[x] = ((unsigned int*)data)[x];
|
||||
for (x = -pad; x < bmw+pad; x++)
|
||||
*(unsigned int *)&out[x*4] = BORDERCOLOUR;
|
||||
out += PLANEWIDTH*4;
|
||||
}
|
||||
for (; y < bmh; y++)
|
||||
{
|
||||
for (x = -pad; x < 0; x++)
|
||||
*(unsigned int *)&out[x*4] = BORDERCOLOUR;
|
||||
for (; x < bmw; x++)
|
||||
((unsigned int*)out)[x] = ((unsigned int*)data)[x];
|
||||
for (; x < bmw+pad; x++)
|
||||
*(unsigned int *)&out[x*4] = BORDERCOLOUR;
|
||||
data = (char*)data + pitch;
|
||||
out += PLANEWIDTH*4;
|
||||
}
|
||||
for (; y < bmh+pad; y++)
|
||||
{
|
||||
for (x = -pad; x < bmw+pad; x++)
|
||||
*(unsigned int *)&out[x*4] = BORDERCOLOUR;
|
||||
out += PLANEWIDTH*4;
|
||||
}
|
||||
}
|
||||
fontplanes.planechanged = true;
|
||||
return c;
|
||||
|
@ -987,6 +1024,7 @@ static texid_t Font_LoadQuakeConchars(void)
|
|||
return r_nulltex;
|
||||
}
|
||||
|
||||
#ifdef HEXEN2
|
||||
static texid_t Font_LoadHexen2Conchars(qboolean iso88591)
|
||||
{
|
||||
//gulp... so it's come to this has it? rework the hexen2 conchars into the q1 system.
|
||||
|
@ -1074,6 +1112,7 @@ static texid_t Font_LoadHexen2Conchars(qboolean iso88591)
|
|||
}
|
||||
return r_nulltex;
|
||||
}
|
||||
#endif
|
||||
|
||||
FTE_ALIGN(4) qbyte default_conchar[/*11356*/] =
|
||||
{
|
||||
|
@ -1328,6 +1367,7 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HEXEN2
|
||||
if (!strcmp(fontfilename, "gfx/tinyfont"))
|
||||
{
|
||||
unsigned int *img;
|
||||
|
@ -1387,6 +1427,7 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename)
|
|||
}
|
||||
return f;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aname)
|
||||
{
|
||||
|
@ -1469,11 +1510,13 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename)
|
|||
if (!TEXLOADED(fontplanes.defaultfont))
|
||||
fontplanes.defaultfont = Font_LoadDefaultConchars();
|
||||
|
||||
#ifdef HEXEN2
|
||||
if (!strcmp(fontfilename, "gfx/hexen2"))
|
||||
{
|
||||
f->singletexture = Font_LoadHexen2Conchars(false);
|
||||
defaultplane = DEFAULTPLANE;
|
||||
}
|
||||
#endif
|
||||
if (!TEXLOADED(f->singletexture))
|
||||
f->singletexture = fontplanes.defaultfont;
|
||||
}
|
||||
|
|
|
@ -5334,7 +5334,11 @@ void Terr_FinishTerrain(model_t *mod)
|
|||
if (qrenderer != QR_NONE)
|
||||
{
|
||||
if (*hm->skyname)
|
||||
{
|
||||
hm->skyshader = R_RegisterCustom(va("skybox_%s", hm->skyname), SUF_NONE, Shader_DefaultSkybox, NULL);
|
||||
if (!hm->skyshader->skydome)
|
||||
hm->skyshader = NULL;
|
||||
}
|
||||
else
|
||||
hm->skyshader = NULL;
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ texture_t *r_notexture_mip = &r_notexture_mip_real;
|
|||
#endif
|
||||
|
||||
void CM_Init(void);
|
||||
void CM_Shutdown(void);
|
||||
|
||||
void Mod_LoadSpriteShaders(model_t *spr);
|
||||
qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer, size_t fsize);
|
||||
|
@ -821,9 +820,6 @@ void Mod_Shutdown (qboolean final)
|
|||
Mod_Purge(MP_RESET);
|
||||
|
||||
Mod_UnRegisterAllModelFormats(NULL);
|
||||
#ifdef Q2BSPS
|
||||
CM_Shutdown();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1528,12 +1524,6 @@ static void Mod_FinishTexture(texture_t *tx, const char *loadname, qboolean safe
|
|||
const char *shadername = tx->name;
|
||||
|
||||
if (!safetoloadfromwads)
|
||||
{
|
||||
|
||||
/*skies? just replace with the override sky*/
|
||||
if (!strncmp(tx->name, "sky", 3) && *cl.skyname)
|
||||
tx->shader = R_RegisterCustom (va("skybox_%s", cl.skyname), SUF_NONE, Shader_DefaultSkybox, NULL); //just load the regular name.
|
||||
else
|
||||
{
|
||||
//remap to avoid bugging out on textures with the same name and different images (vanilla content sucks)
|
||||
shadername = Mod_RemapBuggyTexture(shadername, tx->mips[0], tx->width*tx->height);
|
||||
|
@ -1557,7 +1547,6 @@ static void Mod_FinishTexture(texture_t *tx, const char *loadname, qboolean safe
|
|||
}
|
||||
|
||||
tx->shader = R_RegisterCustom (shadername, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
|
||||
}
|
||||
|
||||
if (!tx->mips[0] && !safetoloadfromwads)
|
||||
return;
|
||||
|
@ -3979,11 +3968,21 @@ static qboolean Mod_LoadNodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, i
|
|||
|
||||
for (j=0 ; j<2 ; j++)
|
||||
{
|
||||
p = LittleShort (in->children[j]);
|
||||
if (p >= 0)
|
||||
p = (unsigned short)LittleShort (in->children[j]);
|
||||
|
||||
if (p >= 0 && p < loadmodel->numnodes)
|
||||
out->children[j] = loadmodel->nodes + p;
|
||||
else
|
||||
out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
|
||||
{
|
||||
p = (-1 - (signed)(0xffff0000|p));
|
||||
if (p >= 0 && p < loadmodel->numleafs)
|
||||
out->children[j] = (mnode_t *)(loadmodel->leafs + p);
|
||||
else
|
||||
{
|
||||
Con_Printf (CON_ERROR "MOD_LoadBmodel: invalid node child %i in %s\n", LittleShort (in->children[j]), loadmodel->name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4813,6 +4812,19 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b)
|
|||
}
|
||||
|
||||
if (mod->fromgame == fg_quake3)
|
||||
{
|
||||
if (mod->lightmaps.deluxemapping && mod->lightmaps.deluxemapping_modelspace)
|
||||
{
|
||||
for(a = 0; a < mod->numtexinfo; a++)
|
||||
{
|
||||
mod->textures[a]->shader = R_RegisterShader_Lightmap(va("%s#BUMPMODELSPACE", mod->textures[a]->name));
|
||||
R_BuildDefaultTexnums(NULL, mod->textures[a]->shader);
|
||||
|
||||
mod->textures[a+mod->numtexinfo]->shader = R_RegisterShader_Vertex (mod->textures[a+mod->numtexinfo]->name);
|
||||
R_BuildDefaultTexnums(NULL, mod->textures[a+mod->numtexinfo]->shader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(a = 0; a < mod->numtexinfo; a++)
|
||||
{
|
||||
|
@ -4822,6 +4834,7 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b)
|
|||
mod->textures[a+mod->numtexinfo]->shader = R_RegisterShader_Vertex (mod->textures[a+mod->numtexinfo]->name);
|
||||
R_BuildDefaultTexnums(NULL, mod->textures[a+mod->numtexinfo]->shader);
|
||||
}
|
||||
}
|
||||
mod->textures[2*mod->numtexinfo]->shader = R_RegisterShader_Flare("noshader");
|
||||
}
|
||||
else if (mod->fromgame == fg_quake2)
|
||||
|
|
|
@ -997,6 +997,7 @@ typedef struct model_s
|
|||
int height; //y size of lightmaps
|
||||
int surfstyles; //numbers of style per surface.
|
||||
qboolean deluxemapping; //lightmaps are interleaved with deluxemap data (lightmap indicies should only be even values)
|
||||
qboolean deluxemapping_modelspace; //deluxemaps are in modelspace - we need different glsl.
|
||||
} lightmaps;
|
||||
|
||||
unsigned checksum;
|
||||
|
|
|
@ -42,6 +42,7 @@ sh_config_t sh_config;
|
|||
//cvars that affect shader generation
|
||||
cvar_t r_vertexlight = CVARFD("r_vertexlight", "0", CVAR_SHADERSYSTEM, "Hack loaded shaders to remove detail pass and lightmap sampling for faster rendering.");
|
||||
cvar_t r_forceprogramify = CVARAFD("r_forceprogramify", "0", "dpcompat_makeshitup", CVAR_SHADERSYSTEM, "Reduce the shader to a single texture, and then make stuff up about its mother. The resulting fist fight results in more colour when you shine a light upon its face.\nSet to 2 to ignore 'depthfunc equal' and 'tcmod scale' in order to tolerate bizzare shaders made for a bizzare engine.\nBecause most shaders made for DP are by people who _clearly_ have no idea what the heck they're doing, you'll typically need the '2' setting.");
|
||||
cvar_t dpcompat_nopremulpics = CVARFD("dpcompat_nopremulpics", "0", CVAR_SHADERSYSTEM, "By default FTE uses premultiplied alpha for hud/2d images, while DP does not (which results in halos with low-res content). Unfortunately DDS files would need to be recompressed, resulting in visible issues.");
|
||||
extern cvar_t r_glsl_offsetmapping_reliefmapping;
|
||||
extern cvar_t r_fastturb, r_fastsky, r_skyboxname;
|
||||
extern cvar_t r_drawflat;
|
||||
|
@ -234,6 +235,9 @@ static struct
|
|||
vec3_t refractcolour;
|
||||
vec3_t reflectcolour;
|
||||
float wateralpha;
|
||||
|
||||
float specularexpscale; //*32 ish
|
||||
float specularvalscale; //*1 ish
|
||||
} parsestate;
|
||||
|
||||
typedef struct shaderkey_s
|
||||
|
@ -552,17 +556,19 @@ static void Shader_ParseVector(shader_t *shader, char **ptr, vec3_t v)
|
|||
}
|
||||
|
||||
qboolean Shader_ParseSkySides (char *shadername, char *texturename, texid_t *images)
|
||||
{
|
||||
{ //FIXME: use Image_LoadCubemapTextureData to load the faces
|
||||
//if possible directly use a 7th/cubemap texture instead
|
||||
//this requires fixing the sky code to not do the random transforms thing though.
|
||||
qboolean allokay = true;
|
||||
int i, ss, sp;
|
||||
char path[MAX_QPATH];
|
||||
|
||||
static char *skyname_suffix[][6] = {
|
||||
{"rt", "bk", "lf", "ft", "up", "dn"},
|
||||
{"px", "py", "nx", "ny", "pz", "nz"},
|
||||
{"posx", "posy", "negx", "negy", "posz", "negz"},
|
||||
{"_px", "_py", "_nx", "_ny", "_pz", "_nz"},
|
||||
{"_posx", "_posy", "_negx", "_negy", "_posz", "_negz"},
|
||||
// {"px", "py", "nx", "ny", "pz", "nz"},
|
||||
// {"posx", "posy", "negx", "negy", "posz", "negz"},
|
||||
// {"_px", "_py", "_nx", "_ny", "_pz", "_nz"},
|
||||
// {"_posx", "_posy", "_negx", "_negy", "_posz", "_negz"},
|
||||
{"_rt", "_bk", "_lf", "_ft", "_up", "_dn"}
|
||||
};
|
||||
|
||||
|
@ -588,6 +594,7 @@ qboolean Shader_ParseSkySides (char *shadername, char *texturename, texid_t *ima
|
|||
if ( texturename[0] == '-' )
|
||||
{
|
||||
images[i] = r_nulltex;
|
||||
allokay = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -596,16 +603,14 @@ qboolean Shader_ParseSkySides (char *shadername, char *texturename, texid_t *ima
|
|||
for (ss = 0; ss < sizeof(skyname_suffix)/sizeof(skyname_suffix[0]); ss++)
|
||||
{
|
||||
Q_snprintfz ( path, sizeof(path), skyname_pattern[sp], texturename, skyname_suffix[ss][i] );
|
||||
images[i] = R_LoadHiResTexture ( path, NULL, IF_NOALPHA|IF_CLAMP|IF_NOWORKER);
|
||||
if (images[i]->status == TEX_LOADING) //FIXME: unsafe, as it can recurse through shader loading and mess up internal parse state.
|
||||
COM_WorkerPartialSync(images[i], &images[i]->status, TEX_LOADING);
|
||||
if (TEXLOADED(images[i]))
|
||||
images[i] = R_LoadHiResTexture ( path, NULL, IF_NOALPHA|IF_CLAMP|IF_LOADNOW);
|
||||
if (images[i]->width)
|
||||
break;
|
||||
}
|
||||
if (TEXLOADED(images[i]))
|
||||
if (images[i]->width)
|
||||
break;
|
||||
}
|
||||
if (!TEXVALID(images[i]))
|
||||
if (!images[i]->width)
|
||||
{
|
||||
Con_Printf("Sky \"%s\" missing texture: %s\n", shadername, path);
|
||||
images[i] = missing_texture;
|
||||
|
@ -916,7 +921,7 @@ static void Shader_SkyParms(shader_t *shader, shaderpass_t *pass, char **ptr)
|
|||
/*skyheight =*/ Shader_ParseFloat(shader, ptr, 512);
|
||||
|
||||
boxname = Shader_ParseString(ptr);
|
||||
Shader_ParseSkySides(shader->name, boxname, skydome->nearbox_textures);
|
||||
// Shader_ParseSkySides(shader->name, boxname, skydome->nearbox_textures);
|
||||
|
||||
shader->flags |= SHADER_SKY;
|
||||
shader->sort = SHADER_SORT_SKY;
|
||||
|
@ -2320,6 +2325,7 @@ static void Shader_Translucent(shader_t *shader, shaderpass_t *pass, char **ptr)
|
|||
static void Shader_DP_Camera(shader_t *shader, shaderpass_t *pass, char **ptr)
|
||||
{
|
||||
shader->sort = SHADER_SORT_PORTAL;
|
||||
parsestate.dpwatertype |= 4;
|
||||
}
|
||||
static void Shader_DP_Water(shader_t *shader, shaderpass_t *pass, char **ptr)
|
||||
{
|
||||
|
@ -2353,6 +2359,38 @@ static void Shader_DP_Refract(shader_t *shader, shaderpass_t *pass, char **ptr)
|
|||
Shader_ParseVector(shader, ptr, parsestate.refractcolour);
|
||||
}
|
||||
|
||||
static void Shader_DP_OffsetMapping(shader_t *shader, shaderpass_t *pass, char **ptr)
|
||||
{
|
||||
char *token = Shader_ParseString(ptr);
|
||||
if (!strcmp(token, "disable") || !strcmp(token, "none") || !strcmp(token, "off"))
|
||||
;
|
||||
else if (!strcmp(token, "default") || !strcmp(token, "normal"))
|
||||
;
|
||||
else if (!strcmp(token, "linear"))
|
||||
;
|
||||
else if (!strcmp(token, "relief"))
|
||||
;
|
||||
/*scale = */Shader_ParseFloat(shader, ptr, 1);
|
||||
token = Shader_ParseString(ptr);
|
||||
if (!strcmp(token, "bias"))
|
||||
/*bias = */Shader_ParseFloat(shader, ptr, 0.5);
|
||||
else if (!strcmp(token, "match"))
|
||||
/*bias = 1.0 - */Shader_ParseFloat(shader, ptr, 0.5);
|
||||
else if (!strcmp(token, "match8"))
|
||||
/*bias = 1.0 - (1.0/255) * */Shader_ParseFloat(shader, ptr, 128);
|
||||
else if (!strcmp(token, "match16"))
|
||||
/*bias = 1.0 - (1.0/65535) * */Shader_ParseFloat(shader, ptr, 32768);
|
||||
}
|
||||
static void Shader_DP_GlossScale(shader_t *shader, shaderpass_t *pass, char **ptr)
|
||||
{
|
||||
parsestate.specularvalscale = Shader_ParseFloat(shader, ptr, 0);
|
||||
}
|
||||
static void Shader_DP_GlossExponent(shader_t *shader, shaderpass_t *pass, char **ptr)
|
||||
{
|
||||
parsestate.specularexpscale = Shader_ParseFloat(shader, ptr, 0);
|
||||
}
|
||||
|
||||
|
||||
static void Shader_BEMode(shader_t *shader, shaderpass_t *pass, char **ptr)
|
||||
{
|
||||
char subname[1024];
|
||||
|
@ -2480,9 +2518,11 @@ static shaderkey_t shaderkeys[] =
|
|||
{"water", Shader_DP_Water, "dp"},
|
||||
{"reflect", Shader_DP_Reflect, "dp"},
|
||||
{"refract", Shader_DP_Refract, "dp"},
|
||||
{"offsetmapping", NULL, "dp"},
|
||||
{"glossintensitymod",NULL, "dp"},
|
||||
{"glossexponentmod",NULL, "dp"},
|
||||
{"offsetmapping", Shader_DP_OffsetMapping, "dp"},
|
||||
{"noshadow", NULL, "dp"},
|
||||
{"polygonoffset", NULL, "dp"},
|
||||
{"glossintensitymod",Shader_DP_GlossScale, "dp"}, //scales r_shadow_glossintensity(=1), aka: gl_specular
|
||||
{"glossexponentmod",Shader_DP_GlossExponent, "dp"}, //scales r_shadow_glossexponent(=32)
|
||||
|
||||
/*doom3 compat*/
|
||||
{"diffusemap", Shader_DiffuseMap, "doom3"}, //macro for "{\nstage diffusemap\nmap <map>\n}"
|
||||
|
@ -2568,6 +2608,14 @@ static qboolean Shaderpass_MapGen (shader_t *shader, shaderpass_t *pass, char *t
|
|||
shader->flags |= SHADER_HASTOPBOTTOM;
|
||||
pass->texgen = T_GEN_LOWEROVERLAY;
|
||||
}
|
||||
else if (!Q_stricmp (tname, "$reflectcube"))
|
||||
{
|
||||
pass->texgen = T_GEN_REFLECTCUBE;
|
||||
}
|
||||
else if (!Q_stricmp (tname, "$reflectmask"))
|
||||
{
|
||||
pass->texgen = T_GEN_REFLECTMASK;
|
||||
}
|
||||
else if (!Q_stricmp (tname, "$shadowmap"))
|
||||
{
|
||||
pass->texgen = T_GEN_SHADOWMAP;
|
||||
|
@ -3291,6 +3339,8 @@ static void Shaderpass_TcGen ( shader_t *shader, shaderpass_t *pass, char **ptr
|
|||
pass->tcgen = TC_GEN_SVECTOR;
|
||||
} else if ( !Q_stricmp (token, "tvector") ) {
|
||||
pass->tcgen = TC_GEN_TVECTOR;
|
||||
} else if ( !Q_stricmp (token, "skybox") ) {
|
||||
pass->tcgen = TC_GEN_SKYBOX;
|
||||
}
|
||||
}
|
||||
static void Shaderpass_EnvMap ( shader_t *shader, shaderpass_t *pass, char **ptr ) //for alienarena
|
||||
|
@ -3784,6 +3834,8 @@ void Shader_Shutdown (void)
|
|||
Shader_FlushCache();
|
||||
Shader_FlushGenerics();
|
||||
|
||||
R_SkyShutdown();
|
||||
|
||||
r_maxshaders = 0;
|
||||
r_numshaders = 0;
|
||||
|
||||
|
@ -4292,13 +4344,13 @@ const char *Shader_AlphaMaskProgArgs(shader_t *s)
|
|||
{
|
||||
default:
|
||||
break;
|
||||
//cases inverted. the test is to enable
|
||||
//cases inverted. the atest is to retain the pixel, glsl is to discard (alpha OP MASK).
|
||||
case SBITS_ATEST_GT0:
|
||||
return "#MASK=0.0#MASKOP=>";
|
||||
return "#MASK=0.0#MASKLT=1";
|
||||
case SBITS_ATEST_LT128:
|
||||
return "#MASK=0.5#MASKOP=<";
|
||||
case SBITS_ATEST_GE128:
|
||||
return "#MASK=0.5";
|
||||
case SBITS_ATEST_GE128:
|
||||
return "#MASK=0.5#MASKLT=1"; //ignore the eq part.
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
@ -4306,9 +4358,10 @@ const char *Shader_AlphaMaskProgArgs(shader_t *s)
|
|||
|
||||
void Shader_Programify (shader_t *s)
|
||||
{
|
||||
qboolean reflectrefract = false;
|
||||
unsigned int reflectrefract = 0;
|
||||
char *prog = NULL;
|
||||
const char *mask;
|
||||
char args[1024];
|
||||
/* enum
|
||||
{
|
||||
T_UNKNOWN,
|
||||
|
@ -4325,9 +4378,19 @@ void Shader_Programify (shader_t *s)
|
|||
else if (pass->rgbgen == RGB_GEN_ENTITY)
|
||||
modellighting = pass;
|
||||
else if (pass->rgbgen == RGB_GEN_VERTEX_LIGHTING || pass->rgbgen == RGB_GEN_VERTEX_EXACT)
|
||||
{
|
||||
if (s->usageflags & (SUF_LIGHTMAP|SUF_2D))
|
||||
vertexlighting = pass;
|
||||
else
|
||||
modellighting = pass; //fucking DP morons who don't know what lightmaps are.
|
||||
}
|
||||
else if (pass->texgen == T_GEN_LIGHTMAP && pass->tcgen == TC_GEN_LIGHTMAP)
|
||||
{
|
||||
if (s->usageflags & SUF_LIGHTMAP)
|
||||
lightmap = pass;
|
||||
else
|
||||
modellighting = pass; //fucking DP morons who don't know what lightmaps are.
|
||||
}
|
||||
|
||||
/*if (pass->numtcmods || (pass->shaderbits & SBITS_ATEST_BITS))
|
||||
return;
|
||||
|
@ -4360,7 +4423,16 @@ void Shader_Programify (shader_t *s)
|
|||
s->passes[0].shaderbits &= ~(SBITS_BLEND_BITS|SBITS_MISC_NODEPTHTEST|SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY);
|
||||
s->passes[0].shaderbits |= SBITS_MISC_DEPTHWRITE;
|
||||
|
||||
reflectrefract = true;
|
||||
if (parsestate.dpwatertype & 1)
|
||||
reflectrefract |= SHADER_HASREFLECT;
|
||||
if (parsestate.dpwatertype & 2)
|
||||
reflectrefract |= SHADER_HASREFRACT;
|
||||
if (parsestate.dpwatertype & 4)
|
||||
{
|
||||
reflectrefract |= SHADER_HASREFRACT|SHADER_HASPORTAL; //doubles up as a 'camera'
|
||||
if (s->sort == SHADER_SORT_PORTAL)
|
||||
s->sort = SHADER_SORT_OPAQUE; //don't do it twice.
|
||||
}
|
||||
}
|
||||
else if (modellighting)
|
||||
{
|
||||
|
@ -4384,9 +4456,19 @@ void Shader_Programify (shader_t *s)
|
|||
return;
|
||||
}
|
||||
|
||||
args[0] = 0;
|
||||
if (parsestate.specularvalscale != 1)
|
||||
Q_strncatz(args, va("#specmul=%g", parsestate.specularvalscale), sizeof(args));
|
||||
if (parsestate.specularexpscale != 1)
|
||||
Q_strncatz(args, va("#specexp=%g", parsestate.specularexpscale), sizeof(args));
|
||||
|
||||
mask = strchr(s->name, '#');
|
||||
if (mask)
|
||||
Q_strncatz(args, mask, sizeof(args));
|
||||
|
||||
mask = Shader_AlphaMaskProgArgs(s);
|
||||
|
||||
s->prog = Shader_FindGeneric(va("%s%s", prog, mask), qrenderer);
|
||||
s->prog = Shader_FindGeneric(va("%s%s%s", prog, mask, args), qrenderer);
|
||||
if (s->prog)
|
||||
{
|
||||
s->numpasses = 0;
|
||||
|
@ -4401,8 +4483,7 @@ void Shader_Programify (shader_t *s)
|
|||
s->passes[s->numpasses++].texgen = T_GEN_REFLECTION;
|
||||
// s->passes[s->numpasses++].texgen = T_GEN_RIPPLEMAP;
|
||||
// s->passes[s->numpasses++].texgen = T_GEN_REFRACTIONDEPTH;
|
||||
s->flags |= SHADER_HASREFRACT;
|
||||
s->flags |= SHADER_HASREFLECT;
|
||||
s->flags |= reflectrefract;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4422,6 +4503,7 @@ void Shader_Finish (shader_t *s)
|
|||
//then the ambient stages.
|
||||
//and forget about the bump/specular stages as we don't support them and already stripped them.
|
||||
|
||||
#if 0
|
||||
if (s->flags & SHADER_SKY)
|
||||
{
|
||||
/*skies go all black if fastsky is set*/
|
||||
|
@ -4449,6 +4531,7 @@ void Shader_Finish (shader_t *s)
|
|||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s->prog && !s->numpasses)
|
||||
{
|
||||
|
@ -4809,7 +4892,6 @@ done:;
|
|||
|
||||
if (!s->prog && sh_config.progs_supported && (r_forceprogramify.ival || parsestate.forceprogramify))
|
||||
{
|
||||
Shader_Programify(s);
|
||||
if (r_forceprogramify.ival >= 2)
|
||||
{
|
||||
if (s->passes[0].numtcmods == 1 && s->passes[0].tcmods[0].type == SHADER_TCMOD_SCALE)
|
||||
|
@ -4818,6 +4900,7 @@ done:;
|
|||
s->passes[0].shaderbits = (s->passes[0].shaderbits & ~SBITS_ATEST_BITS) | SBITS_ATEST_GE128;
|
||||
s->passes[0].shaderbits &= ~SBITS_MISC_DEPTHEQUALONLY; //DP ignores this too.
|
||||
}
|
||||
Shader_Programify(s);
|
||||
}
|
||||
|
||||
if (s->prog)
|
||||
|
@ -5515,13 +5598,27 @@ void Shader_DefaultCinematic(const char *shortname, shader_t *s, const void *arg
|
|||
/*shortname should begin with 'skybox_'*/
|
||||
void Shader_DefaultSkybox(const char *shortname, shader_t *s, const void *args)
|
||||
{
|
||||
int i;
|
||||
Shader_DefaultScript(shortname, s,
|
||||
va(
|
||||
"{\n"
|
||||
"sort sky\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"skyparms %s - -\n"
|
||||
"}\n"
|
||||
, shortname+7)
|
||||
);
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
if (s->skydome->farbox_textures[i] == missing_texture)
|
||||
{
|
||||
if (s->skydome)
|
||||
Z_Free(s->skydome);
|
||||
s->skydome = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *Shader_DefaultBSPWater(shader_t *s, const char *shortname)
|
||||
|
@ -5741,7 +5838,6 @@ void Shader_DefaultBSPQ2(const char *shortname, shader_t *s, const void *args)
|
|||
"{\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"skyparms - - -\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
@ -5812,7 +5908,7 @@ void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args)
|
|||
if (!builtin && !strncmp(shortname, "sky", 3))
|
||||
{
|
||||
//q1 sky
|
||||
if (r_fastsky.ival)
|
||||
/*if (r_fastsky.ival)
|
||||
{
|
||||
builtin = (
|
||||
"{\n"
|
||||
|
@ -5824,23 +5920,23 @@ void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args)
|
|||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
else if (*r_skyboxname.string || *cl.skyname)
|
||||
}*/
|
||||
/*else if (*r_skyboxname.string || *cl.skyname)
|
||||
{
|
||||
builtin = (
|
||||
"{\n"
|
||||
"sort sky\n"
|
||||
"skyparms $r_skybox - -\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
);
|
||||
Shader_DefaultScript(shortname, s, builtin);
|
||||
if (s->flags & SHADER_SKY)
|
||||
qboolean okay;
|
||||
Z_Free(s->skydome);
|
||||
s->skydome = (skydome_t *)Z_Malloc(sizeof(skydome_t));
|
||||
|
||||
okay = Shader_ParseSkySides(shortname, "", s->skydome->farbox_textures);
|
||||
s->flags |= SHADER_SKY|SHADER_NODLIGHT;
|
||||
s->sort = SHADER_SORT_SKY;
|
||||
|
||||
if (okay)
|
||||
return;
|
||||
builtin = NULL;
|
||||
/*if the r_skybox failed to load or whatever, reset and fall through and just use the regular sky*/
|
||||
//if the r_skybox failed to load or whatever, reset and fall through and just use the regular sky
|
||||
Shader_Reset(s);
|
||||
}
|
||||
}*/
|
||||
if (!builtin)
|
||||
builtin = (
|
||||
"{\n"
|
||||
|
@ -6066,7 +6162,7 @@ void Shader_Default2D(const char *shortname, shader_t *s, const void *genargs)
|
|||
{
|
||||
if (Shader_ParseShader("default2d", s))
|
||||
return;
|
||||
if (sh_config.progs_supported && qrenderer != QR_DIRECT3D9)
|
||||
if (sh_config.progs_supported && qrenderer != QR_DIRECT3D9 && !dpcompat_nopremulpics.ival)
|
||||
{
|
||||
//hexen2 needs premultiplied alpha to avoid looking ugly
|
||||
//but that results in problems where things are drawn with alpha not 0, so scale vertex colour by alpha in the fragment program
|
||||
|
@ -6211,6 +6307,8 @@ static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode)
|
|||
|
||||
memset(&parsestate, 0, sizeof(parsestate));
|
||||
parsestate.mode = parsemode;
|
||||
parsestate.specularexpscale = 1;
|
||||
parsestate.specularvalscale = 1;
|
||||
|
||||
if (!s->defaulttextures)
|
||||
{
|
||||
|
@ -6432,45 +6530,10 @@ static shader_t *R_LoadShader (const char *name, unsigned int usageflags, shader
|
|||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
char *Shader_Decompose(shader_t *s)
|
||||
static char *Shader_DecomposePass(char *o, shaderpass_t *p, qboolean simple)
|
||||
{
|
||||
static char decomposebuf[32768];
|
||||
char *o = decomposebuf;
|
||||
sprintf(o, "<---\n"); o+=strlen(o);
|
||||
|
||||
switch (s->sort)
|
||||
if (!simple)
|
||||
{
|
||||
case SHADER_SORT_NONE: sprintf(o, "sort %i (SHADER_SORT_NONE)\n", s->sort); break;
|
||||
case SHADER_SORT_RIPPLE: sprintf(o, "sort %i (SHADER_SORT_RIPPLE)\n", s->sort); break;
|
||||
case SHADER_SORT_PRELIGHT: sprintf(o, "sort %i (SHADER_SORT_PRELIGHT)\n", s->sort); break;
|
||||
case SHADER_SORT_PORTAL: sprintf(o, "sort %i (SHADER_SORT_PORTAL)\n", s->sort); break;
|
||||
case SHADER_SORT_SKY: sprintf(o, "sort %i (SHADER_SORT_SKY)\n", s->sort); break;
|
||||
case SHADER_SORT_OPAQUE: sprintf(o, "sort %i (SHADER_SORT_OPAQUE)\n", s->sort); break;
|
||||
case SHADER_SORT_DECAL: sprintf(o, "sort %i (SHADER_SORT_DECAL)\n", s->sort); break;
|
||||
case SHADER_SORT_SEETHROUGH:sprintf(o, "sort %i (SHADER_SORT_SEETHROUGH)\n", s->sort); break;
|
||||
case SHADER_SORT_BANNER: sprintf(o, "sort %i (SHADER_SORT_BANNER)\n", s->sort); break;
|
||||
case SHADER_SORT_UNDERWATER:sprintf(o, "sort %i (SHADER_SORT_UNDERWATER)\n", s->sort); break;
|
||||
case SHADER_SORT_BLEND: sprintf(o, "sort %i (SHADER_SORT_BLEND)\n", s->sort); break;
|
||||
case SHADER_SORT_ADDITIVE: sprintf(o, "sort %i (SHADER_SORT_ADDITIVE)\n", s->sort); break;
|
||||
case SHADER_SORT_NEAREST: sprintf(o, "sort %i (SHADER_SORT_NEAREST)\n", s->sort); break;
|
||||
default: sprintf(o, "sort %i\n", s->sort); break;
|
||||
}
|
||||
o+=strlen(o);
|
||||
|
||||
if (s->prog)
|
||||
{
|
||||
sprintf(o, "program\n");
|
||||
o+=strlen(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i, j;
|
||||
shaderpass_t *p;
|
||||
for (i = 0; i < s->numpasses; i+= p->numMergedPasses)
|
||||
{
|
||||
p = &s->passes[i];
|
||||
sprintf(o, "{\n"); o+=strlen(o);
|
||||
|
||||
switch(p->rgbgen)
|
||||
{
|
||||
case RGB_GEN_ENTITY: sprintf(o, "RGB_GEN_ENTITY "); break;
|
||||
|
@ -6490,6 +6553,7 @@ char *Shader_Decompose(shader_t *s)
|
|||
}
|
||||
o+=strlen(o);
|
||||
sprintf(o, "\n"); o+=strlen(o);
|
||||
}
|
||||
|
||||
if (p->shaderbits & SBITS_MISC_DEPTHWRITE) { sprintf(o, "SBITS_MISC_DEPTHWRITE\n"); o+=strlen(o); }
|
||||
if (p->shaderbits & SBITS_MISC_NODEPTHTEST) { sprintf(o, "SBITS_MISC_NODEPTHTEST\n"); o+=strlen(o); }
|
||||
|
@ -6550,10 +6614,13 @@ char *Shader_Decompose(shader_t *s)
|
|||
case SBITS_ATEST_GT0: sprintf(o, "SBITS_ATEST_GT0\n"); break;
|
||||
}
|
||||
o+=strlen(o);
|
||||
|
||||
for (j = 0; j < p->numMergedPasses; j++)
|
||||
return o;
|
||||
}
|
||||
static char *Shader_DecomposeSubPass(char *o, shaderpass_t *p, qboolean simple)
|
||||
{
|
||||
switch(p[j].blendmode)
|
||||
if (!simple)
|
||||
{
|
||||
switch(p->blendmode)
|
||||
{
|
||||
default:
|
||||
case PBM_MODULATE: sprintf(o, "modulate "); break;
|
||||
|
@ -6566,14 +6633,15 @@ char *Shader_Decompose(shader_t *s)
|
|||
case PBM_MODULATE_PREV_COLOUR: sprintf(o, "modulate_prev "); break;
|
||||
}
|
||||
o+=strlen(o);
|
||||
}
|
||||
|
||||
switch(p[j].texgen)
|
||||
switch(p->texgen)
|
||||
{
|
||||
default:
|
||||
case T_GEN_SINGLEMAP:
|
||||
if (p[j].anim_frames[0])
|
||||
if (p->anim_frames[0])
|
||||
{
|
||||
sprintf(o, "singlemap \"%s\" %ix%i", p[j].anim_frames[0]->ident, p[j].anim_frames[0]->width, p[j].anim_frames[0]->height);
|
||||
sprintf(o, "singlemap \"%s\" %ix%i", p->anim_frames[0]->ident, p->anim_frames[0]->width, p->anim_frames[0]->height);
|
||||
}
|
||||
else
|
||||
sprintf(o, "singlemap ");
|
||||
|
@ -6607,7 +6675,56 @@ char *Shader_Decompose(shader_t *s)
|
|||
o+=strlen(o);
|
||||
|
||||
sprintf(o, "\n"); o+=strlen(o);
|
||||
return o;
|
||||
}
|
||||
char *Shader_Decompose(shader_t *s)
|
||||
{
|
||||
static char decomposebuf[32768];
|
||||
char *o = decomposebuf;
|
||||
shaderpass_t *p;
|
||||
unsigned int i, j;
|
||||
|
||||
sprintf(o, "\n<---\n"); o+=strlen(o);
|
||||
|
||||
switch (s->sort)
|
||||
{
|
||||
case SHADER_SORT_NONE: sprintf(o, "sort %i (SHADER_SORT_NONE)\n", s->sort); break;
|
||||
case SHADER_SORT_RIPPLE: sprintf(o, "sort %i (SHADER_SORT_RIPPLE)\n", s->sort); break;
|
||||
case SHADER_SORT_PRELIGHT: sprintf(o, "sort %i (SHADER_SORT_PRELIGHT)\n", s->sort); break;
|
||||
case SHADER_SORT_PORTAL: sprintf(o, "sort %i (SHADER_SORT_PORTAL)\n", s->sort); break;
|
||||
case SHADER_SORT_SKY: sprintf(o, "sort %i (SHADER_SORT_SKY)\n", s->sort); break;
|
||||
case SHADER_SORT_OPAQUE: sprintf(o, "sort %i (SHADER_SORT_OPAQUE)\n", s->sort); break;
|
||||
case SHADER_SORT_DECAL: sprintf(o, "sort %i (SHADER_SORT_DECAL)\n", s->sort); break;
|
||||
case SHADER_SORT_SEETHROUGH:sprintf(o, "sort %i (SHADER_SORT_SEETHROUGH)\n", s->sort); break;
|
||||
case SHADER_SORT_BANNER: sprintf(o, "sort %i (SHADER_SORT_BANNER)\n", s->sort); break;
|
||||
case SHADER_SORT_UNDERWATER:sprintf(o, "sort %i (SHADER_SORT_UNDERWATER)\n", s->sort); break;
|
||||
case SHADER_SORT_BLEND: sprintf(o, "sort %i (SHADER_SORT_BLEND)\n", s->sort); break;
|
||||
case SHADER_SORT_ADDITIVE: sprintf(o, "sort %i (SHADER_SORT_ADDITIVE)\n", s->sort); break;
|
||||
case SHADER_SORT_NEAREST: sprintf(o, "sort %i (SHADER_SORT_NEAREST)\n", s->sort); break;
|
||||
default: sprintf(o, "sort %i\n", s->sort); break;
|
||||
}
|
||||
o+=strlen(o);
|
||||
|
||||
if (s->prog)
|
||||
{
|
||||
sprintf(o, "program\n");
|
||||
o+=strlen(o);
|
||||
|
||||
p = s->passes;
|
||||
o = Shader_DecomposePass(o, p, true);
|
||||
for (j = 0; j < s->numpasses; j++)
|
||||
o = Shader_DecomposeSubPass(o, p+j, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < s->numpasses; i+= p->numMergedPasses)
|
||||
{
|
||||
p = &s->passes[i];
|
||||
sprintf(o, "{\n"); o+=strlen(o);
|
||||
|
||||
o = Shader_DecomposePass(o, p, false);
|
||||
for (j = 0; j < p->numMergedPasses; j++)
|
||||
o = Shader_DecomposeSubPass(o, p+j, false);
|
||||
sprintf(o, "}\n"); o+=strlen(o);
|
||||
}
|
||||
}
|
||||
|
@ -6618,7 +6735,7 @@ char *Shader_Decompose(shader_t *s)
|
|||
|
||||
char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize)
|
||||
{
|
||||
char *adr, *parsename=NULL;
|
||||
char *adr, *parsename=NULL, *argsstart;
|
||||
char cleanname[MAX_QPATH];
|
||||
char shortname[MAX_QPATH];
|
||||
char drivername[MAX_QPATH];
|
||||
|
@ -6632,8 +6749,11 @@ char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize)
|
|||
saveshaderbody = &adr;
|
||||
|
||||
strcpy(cleanname, s->name);
|
||||
argsstart = strchr(cleanname, '#');
|
||||
if (argsstart)
|
||||
*argsstart = 0;
|
||||
COM_StripExtension (cleanname, shortname, sizeof(shortname));
|
||||
if (ruleset_allow_shaders.ival)
|
||||
if (ruleset_allow_shaders.ival && !(s->usageflags & SUR_FORCEFALLBACK))
|
||||
{
|
||||
if (sh_config.shadernamefmt)
|
||||
{
|
||||
|
@ -6777,7 +6897,7 @@ void Shader_DoReload(void)
|
|||
shader_t *s;
|
||||
unsigned int i;
|
||||
char shortname[MAX_QPATH];
|
||||
char cleanname[MAX_QPATH];
|
||||
char cleanname[MAX_QPATH], *argsstart;
|
||||
int oldsort;
|
||||
qboolean resort = false;
|
||||
|
||||
|
@ -6821,8 +6941,11 @@ void Shader_DoReload(void)
|
|||
continue;
|
||||
|
||||
strcpy(cleanname, s->name);
|
||||
argsstart = strchr(cleanname, '#');
|
||||
if (argsstart)
|
||||
*argsstart = 0;
|
||||
COM_StripExtension (cleanname, shortname, sizeof(shortname));
|
||||
if (ruleset_allow_shaders.ival)
|
||||
if (ruleset_allow_shaders.ival && !(s->usageflags & SUR_FORCEFALLBACK))
|
||||
{
|
||||
if (sh_config.shadernamefmt)
|
||||
{
|
||||
|
|
|
@ -1243,6 +1243,14 @@ static const char *glsl_hdrs[] =
|
|||
"#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must
|
||||
"#define sampler2DShadow sampler2D\n"
|
||||
"#endif\n"
|
||||
"#ifndef SPECEXP\n"
|
||||
"#define SPECEXP 1.0\n"
|
||||
"#endif\n"
|
||||
"#define FTE_SPECULAR_EXPONENT (32.0*float(SPECEXP))\n"
|
||||
"#ifndef SPECMUL\n"
|
||||
"#define SPECMUL 1.0\n"
|
||||
"#endif\n"
|
||||
"#define FTE_SPECULAR_MULTIPLIER (cvar_gl_specular*float(SPECMUL))\n"
|
||||
#ifndef NOLEGACY
|
||||
"uniform sampler2DShadow s_shadowmap;"
|
||||
"uniform samplerCube s_projectionmap;"
|
||||
|
@ -2854,12 +2862,16 @@ void GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
|
|||
sh_config.shadernamefmt = "%s_gles";
|
||||
|
||||
sh_config.can_mipcap = gl_config.glversion >= 3.0;
|
||||
|
||||
sh_config.havecubemaps = gl_config.glversion >= 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
GLint srgb = gl_config.glversion >= 2.1 || GL_CheckExtension("GL_EXT_texture_sRGB"); //became core in gl 2.1
|
||||
sh_config.can_mipcap = gl_config.glversion >= 1.2;
|
||||
|
||||
sh_config.havecubemaps = gl_config.glversion >= 1.3; //cubemaps AND clamp-to-edge.
|
||||
|
||||
sh_config.texfmt[PTI_RGBX8] = true; //proper support
|
||||
|
||||
//these require stuff like GL_UNSIGNED_SHORT_5_5_5_1 etc, which needs gl 1.2+
|
||||
|
|
|
@ -1403,29 +1403,38 @@ qboolean GLVID_ApplyGammaRamps(unsigned int rampcount, unsigned short *ramps)
|
|||
if (!vm.originalapplied)
|
||||
return false;
|
||||
|
||||
if (ramps || rampcount != vm.originalrampsize)
|
||||
if (ramps && rampcount == vm.originalrampsize)
|
||||
{
|
||||
//hardwaregamma==1 skips hardware gamma when we're not fullscreen, in favour of software glsl based gamma.
|
||||
// if (vid_hardwaregamma.value == 1 && !vid.activeapp && !(fullscreenflags & FULLSCREEN_ACTIVE))
|
||||
// return false;
|
||||
// if (!vid.activeapp)
|
||||
// return false;
|
||||
// if (!vid_hardwaregamma.value)
|
||||
// return false;
|
||||
switch(vid_hardwaregamma.ival)
|
||||
{
|
||||
case 0: //never use hardware/glsl gamma
|
||||
case 2: //ALWAYS use glsl gamma
|
||||
return false;
|
||||
default:
|
||||
case 1: //no hardware gamma when windowed
|
||||
if (!(fullscreenflags & FULLSCREEN_ACTIVE))
|
||||
return false;
|
||||
break;
|
||||
case 3: //ALWAYS try to use hardware gamma, even when it fails...
|
||||
break;
|
||||
}
|
||||
|
||||
//we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma if it randomly fails (yuck)
|
||||
if (vid.activeapp)
|
||||
{
|
||||
if (gammaworks)
|
||||
vm.pXF86VidModeSetGammaRamp (vid_dpy, scrnum, rampcount, &ramps[0], &ramps[rampcount], &ramps[rampcount*2]);
|
||||
else
|
||||
gammaworks = !!vm.pXF86VidModeSetGammaRamp (vid_dpy, scrnum, rampcount, &ramps[0], &ramps[rampcount], &ramps[rampcount*2]);
|
||||
|
||||
return gammaworks;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (gammaworks)
|
||||
{
|
||||
vm.pXF86VidModeSetGammaRamp(vid_dpy, scrnum, vm.originalrampsize, vm.originalramps[0], vm.originalramps[1], vm.originalramps[2]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLVID_SwapBuffers (void)
|
||||
|
|
|
@ -2137,15 +2137,21 @@ qboolean GLVID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short *ramp
|
|||
{
|
||||
if (ramps)
|
||||
{
|
||||
if (!gammaworks || gammarampsize != 256)
|
||||
return false;
|
||||
|
||||
if (vid_hardwaregamma.value == 1 && modestate == MS_WINDOWED)
|
||||
return false; //don't do hardware gamma in windowed mode
|
||||
|
||||
if (vid.activeapp && vid_hardwaregamma.value) //this is needed because ATI drivers don't work properly (or when task-switched out).
|
||||
switch(vid_hardwaregamma.ival)
|
||||
{
|
||||
if (gammaworks)
|
||||
case 0: //never use hardware/glsl gamma
|
||||
case 2: //ALWAYS use glsl gamma
|
||||
return false;
|
||||
default:
|
||||
case 1: //no hardware gamma when windowed
|
||||
if (modestate == MS_WINDOWED)
|
||||
return false;
|
||||
break;
|
||||
case 3: //ALWAYS try to use hardware gamma, even when it fails...
|
||||
break;
|
||||
}
|
||||
|
||||
if (vid.activeapp) //this is needed because ATI drivers don't work properly (or when task-switched out).
|
||||
{ //we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma (yuck)
|
||||
if (vid_desktopgamma.value)
|
||||
{
|
||||
|
@ -2157,12 +2163,11 @@ qboolean GLVID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short *ramp
|
|||
{
|
||||
qSetDeviceGammaRamp (maindc, ramps);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
else if (gammaworks)
|
||||
{
|
||||
//revert to default
|
||||
if (qSetDeviceGammaRamp)
|
||||
|
@ -2182,6 +2187,7 @@ qboolean GLVID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short *ramp
|
|||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLVID_Crashed(void)
|
||||
|
|
|
@ -333,21 +333,24 @@ qboolean GLVID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short *ramp
|
|||
#if SDL_MAJOR_VERSION >= 2
|
||||
if (ramps && gammarampsize == 256)
|
||||
{
|
||||
if (vid_hardwaregamma.value)
|
||||
switch(vid_hardwaregamma.ival)
|
||||
{
|
||||
if (gammaworks)
|
||||
{ //we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma (yuck)
|
||||
SDL_SetWindowGammaRamp (sdlwindow, &ramps[0], &ramps[256], &ramps[512]);
|
||||
return true;
|
||||
case 0: //never use hardware/glsl gamma
|
||||
case 2: //ALWAYS use glsl gamma
|
||||
return false;
|
||||
default:
|
||||
case 1: //no hardware gamma when windowed
|
||||
if (!vid_isfullscreen)
|
||||
return false;
|
||||
break;
|
||||
case 3: //ALWAYS try to use hardware gamma, even when it fails...
|
||||
break;
|
||||
}
|
||||
gammaworks = !SDL_SetWindowGammaRamp (sdlwindow, &ramps[0], &ramps[256], &ramps[512]);
|
||||
}
|
||||
else
|
||||
gammaworks = false;
|
||||
|
||||
gammaworks |= !SDL_SetWindowGammaRamp (sdlwindow, &ramps[0], &ramps[256], &ramps[512]);
|
||||
return gammaworks;
|
||||
}
|
||||
else
|
||||
else if (gammaworks)
|
||||
{
|
||||
SDL_SetWindowGammaRamp (sdlwindow, NULL, NULL, NULL);
|
||||
return true;
|
||||
|
@ -355,18 +358,21 @@ qboolean GLVID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short *ramp
|
|||
#else
|
||||
if (ramps && gammarampsize == 256)
|
||||
{
|
||||
if (vid_hardwaregamma.value)
|
||||
switch(vid_hardwaregamma.ival)
|
||||
{
|
||||
if (gammaworks)
|
||||
{ //we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma (yuck)
|
||||
SDL_SetGammaRamp (&ramps[0], &ramps[256], &ramps[512]);
|
||||
return true;
|
||||
case 0: //never use hardware/glsl gamma
|
||||
case 2: //ALWAYS use glsl gamma
|
||||
return false;
|
||||
default:
|
||||
case 1: //no hardware gamma when windowed
|
||||
if (!vid_isfullscreen)
|
||||
return false;
|
||||
break;
|
||||
case 3: //ALWAYS try to use hardware gamma, even when it fails...
|
||||
break;
|
||||
}
|
||||
gammaworks = !SDL_SetGammaRamp (&ramps[0], &ramps[256], &ramps[512]);
|
||||
}
|
||||
else
|
||||
gammaworks = false;
|
||||
|
||||
gammaworks |= !SDL_SetGammaRamp (&ramps[0], &ramps[256], &ramps[512]);
|
||||
return gammaworks;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -36,7 +36,7 @@ extern cvar_t gl_skyboxdist;
|
|||
extern cvar_t r_fastsky;
|
||||
extern cvar_t r_fastskycolour;
|
||||
|
||||
static shader_t *forcedskyshader;
|
||||
static shader_t *forcedsky;
|
||||
static shader_t *skyboxface;
|
||||
static shader_t *skygridface;
|
||||
|
||||
|
@ -44,47 +44,77 @@ static shader_t *skygridface;
|
|||
|
||||
//=========================================================
|
||||
|
||||
void R_SetSky(char *skyname)
|
||||
//called on video shutdown to reset internal state
|
||||
void R_SkyShutdown(void)
|
||||
{
|
||||
extern cvar_t r_skyboxname;
|
||||
forcedskyshader = NULL;
|
||||
|
||||
if (!qrenderer)
|
||||
return;
|
||||
|
||||
if (*r_skyboxname.string) //user's setting overrides.
|
||||
skyname = r_skyboxname.string;
|
||||
|
||||
Shader_NeedReload(false);
|
||||
if (*skyname)
|
||||
forcedskyshader = R_RegisterCustom(va("skybox_%s", skyname), SUF_NONE, Shader_DefaultSkybox, NULL);
|
||||
|
||||
skyboxface = R_RegisterShader("skyboxface", SUF_NONE,
|
||||
"{\n"
|
||||
"program default2d\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"nodepth\n" //don't write depth. this stuff is meant to be an infiniteish distance away.
|
||||
"}\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
skygridface = R_RegisterShader("skygridface", SUF_NONE,
|
||||
"{\n"
|
||||
"program default2d\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"nodepth\n" //don't write depth. this stuff is meant to be an infiniteish distance away.
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $fullbright\n"
|
||||
"blendfunc blend\n"
|
||||
"nodepth\n" //don't write depth. this stuff is meant to be an infiniteish distance away.
|
||||
"}\n"
|
||||
"}\n"
|
||||
);
|
||||
skyboxface = NULL;
|
||||
skygridface = NULL;
|
||||
forcedsky = NULL;
|
||||
}
|
||||
|
||||
void R_SetSky(const char *sky)
|
||||
{
|
||||
int i;
|
||||
const char *shadername;
|
||||
extern cvar_t r_skyboxname;
|
||||
Q_strncpyz(cl.skyname, sky, sizeof(cl.skyname));
|
||||
if (*r_skyboxname.string) //override it with the user's preference
|
||||
sky = r_skyboxname.string;
|
||||
|
||||
shadername = va("skybox_%s", sky);
|
||||
if (!forcedsky || strcmp(shadername, forcedsky->name))
|
||||
{
|
||||
forcedsky = NULL; //fall back to regular skies if forcing fails.
|
||||
|
||||
if (!*sky)
|
||||
return; //no need to do anything
|
||||
|
||||
//if we have cubemaps then we can just go and use a cubemap for our skybox
|
||||
if (sh_config.havecubemaps)
|
||||
{
|
||||
texnums_t tex;
|
||||
memset(&tex, 0, sizeof(tex));
|
||||
tex.reflectcube = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_CUBEMAP|IF_CLAMP);
|
||||
if (tex.reflectcube->width)
|
||||
{
|
||||
forcedsky = R_RegisterShader(va("skybox_%s", sky), 0, va("{\nsort sky\nprogram defaultskybox\n{\nmap \"$cube:$reflectcube\"\ntcgen skybox\n}\nsurfaceparms nodlight\nsurfaceparms sky\n}", sky));
|
||||
R_BuildDefaultTexnums(&tex, forcedsky);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//crappy old path that I still need to fix up a bit
|
||||
//unlike cubemaps, this works on gl1.1/gles1, and also works with the different faces as different sizes.
|
||||
forcedsky = R_RegisterShader(shadername, 0, va("{\nsort sky\nskyparms \"%s\" 512 -\nsurfaceparms nodlight\n}", sky));
|
||||
//check that we actually got some textures.
|
||||
//we accept the skybox if even 1 face is valid.
|
||||
//we ignore the replacement only request if all are invalid.
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
extern texid_t missing_texture;
|
||||
if (forcedsky->skydome && forcedsky->skydome->farbox_textures[i] != missing_texture)
|
||||
break;
|
||||
}
|
||||
if (i == 6) //couldn't find ANY sky textures.
|
||||
forcedsky = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void R_DrawFastSky(batch_t *batch)
|
||||
{
|
||||
batch_t b = *batch;
|
||||
b.shader = R_RegisterShader("fastsky", 0, "{\n"
|
||||
"sort sky\n"
|
||||
"{\n"
|
||||
"map $whiteimage\n"
|
||||
"rgbgen const $r_fastskycolour\n"
|
||||
"}\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n");
|
||||
b.skin = NULL;
|
||||
b.texture = NULL;
|
||||
BE_SubmitBatch(&b);
|
||||
}
|
||||
/*
|
||||
=================
|
||||
GL_DrawSkyChain
|
||||
|
@ -95,13 +125,32 @@ qboolean R_DrawSkyChain (batch_t *batch)
|
|||
shader_t *skyshader;
|
||||
texid_t *skyboxtex;
|
||||
|
||||
if (forcedskyshader)
|
||||
skyshader = forcedskyshader;
|
||||
else
|
||||
skyshader = batch->shader;
|
||||
if (r_fastsky.value)
|
||||
{
|
||||
R_DrawFastSky(batch);
|
||||
return true; //depth will always be drawn with this pathway.
|
||||
}
|
||||
|
||||
if (skyshader->prog || !skyboxface)
|
||||
if (forcedsky)
|
||||
{
|
||||
skyshader = forcedsky;
|
||||
|
||||
if (forcedsky->numpasses)
|
||||
{ //cubemap skies!
|
||||
batch_t b = *batch;
|
||||
b.shader = forcedsky;
|
||||
b.skin = NULL;
|
||||
b.texture = NULL;
|
||||
BE_SubmitBatch(&b);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skyshader = batch->shader;
|
||||
if (skyshader->prog) //glsl is expected to do the whole skybox/warpsky thing itself, with no assistance from this legacy code.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (skyshader->skydome)
|
||||
skyboxtex = skyshader->skydome->farbox_textures;
|
||||
|
@ -126,6 +175,11 @@ qboolean R_DrawSkyChain (batch_t *batch)
|
|||
else
|
||||
GL_DrawSkySphere(batch, skyshader);
|
||||
}
|
||||
else if (batch->meshes)
|
||||
{ //if you had wanted it invisible, you should have used nodraw.
|
||||
R_DrawFastSky(batch);
|
||||
return true; //depth will always be drawn with this pathway.
|
||||
}
|
||||
|
||||
//neither skydomes nor skyboxes nor skygrids will have been drawn with the correct depth values for the sky.
|
||||
//this can result in rooms behind the sky surfaces being visible.
|
||||
|
@ -387,7 +441,7 @@ static void R_CalcSkyChainBounds (batch_t *batch)
|
|||
for (m = batch->firstmesh; m < batch->meshes; m++)
|
||||
{
|
||||
mesh = batch->mesh[m];
|
||||
if (!mesh->xyz_array)
|
||||
if (!mesh->xyz_array || !mesh->indexes)
|
||||
continue;
|
||||
//triangulate
|
||||
for (i = 0; i < mesh->numindexes; i+=3)
|
||||
|
@ -714,6 +768,22 @@ static void GL_DrawSkyGrid (texnums_t *tex)
|
|||
skyent.axis[2][2] = 1;
|
||||
skyent.scale = 1;
|
||||
|
||||
if (!skygridface)
|
||||
skygridface = R_RegisterShader("skygridface", SUF_NONE,
|
||||
"{\n"
|
||||
"program default2d\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"nodepth\n" //don't write depth. this stuff is meant to be an infiniteish distance away.
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $fullbright\n"
|
||||
"blendfunc blend\n"
|
||||
"nodepth\n" //don't write depth. this stuff is meant to be an infiniteish distance away.
|
||||
"}\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
//FIXME: We should use the skybox clipping code and split the sphere into 6 sides.
|
||||
b.meshes = 1;
|
||||
b.firstmesh = 0;
|
||||
|
@ -773,6 +843,17 @@ static void GL_DrawSkyBox (texid_t *texnums, batch_t *s)
|
|||
skyfacemesh.numindexes = 6;
|
||||
skyfacemesh.numvertexes = 4;
|
||||
|
||||
if (!skyboxface)
|
||||
skyboxface = R_RegisterShader("skyboxface", SUF_NONE,
|
||||
"{\n"
|
||||
"program default2d\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"nodepth\n" //don't write depth. this stuff is meant to be an infiniteish distance away.
|
||||
"}\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
if (skymins[0][i] >= skymaxs[0][i]
|
||||
|
|
|
@ -143,6 +143,7 @@ struct relight_ctx_s *LightStartup(struct relight_ctx_s *ctx, model_t *model, qb
|
|||
ctx->shadows = shadows;
|
||||
ctx->skiplit = skiplit;
|
||||
}
|
||||
if (ctx->nummodels < countof(ctx->models))
|
||||
ctx->models[ctx->nummodels++] = model;
|
||||
return ctx;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -504,7 +504,7 @@ typedef struct programshared_s
|
|||
void *hull;
|
||||
void *domain;
|
||||
void *geom;
|
||||
void *layout;
|
||||
void *layouts[2];
|
||||
#endif
|
||||
} hlsl;
|
||||
#endif
|
||||
|
@ -606,6 +606,7 @@ struct shader_s
|
|||
SHADER_HASDIFFUSE = 1 << 27, //has a T_GEN_DIFFUSE pass
|
||||
SHADER_HASPALETTED = 1 << 28, //has a T_GEN_PALETTED pass
|
||||
SHADER_HASCURRENTRENDER = 1 << 29, //has a $currentrender pass
|
||||
SHADER_HASPORTAL = 1 << 30, //reflection image is actually a portal rather than a simple reflection (must be paired with SHADER_HASREFRACT)
|
||||
} flags;
|
||||
|
||||
program_t *prog;
|
||||
|
@ -733,6 +734,7 @@ typedef struct
|
|||
qboolean nv_tex_env_combine4;
|
||||
qboolean env_add;
|
||||
qboolean can_mipcap; //
|
||||
qboolean havecubemaps; //since gl1.3, so pretty much everyone will have this... should probably only be set if we also have seamless or clamp-to-edge.
|
||||
|
||||
void (*pDeleteProg) (program_t *prog);
|
||||
qboolean (*pLoadBlob) (program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile);
|
||||
|
|
|
@ -1022,25 +1022,25 @@ r_part teq2_heatbeam_steam
|
|||
{ //FIXME
|
||||
assoc placeholder
|
||||
}
|
||||
/*
|
||||
r_part teq2_heatbeam_steam
|
||||
{
|
||||
count 20
|
||||
colorindex 0xe0 7
|
||||
// magnitude 60
|
||||
texture "classicparticle"
|
||||
tcoords 0 0 16 16 32
|
||||
scale 1
|
||||
alpha 1
|
||||
die 0.3 0.8
|
||||
randomvel 20 magnitude/3
|
||||
veladd magnitude
|
||||
orgadd magnitude/10
|
||||
spawnorg 4
|
||||
gravity -400
|
||||
scalefactor 0.8
|
||||
}
|
||||
*/
|
||||
|
||||
//r_part teq2_heatbeam_steam
|
||||
//{
|
||||
// count 20
|
||||
// colorindex 0xe0 7
|
||||
//// magnitude 60
|
||||
// texture "classicparticle"
|
||||
// tcoords 0 0 16 16 32
|
||||
// scale 1
|
||||
// alpha 1
|
||||
// die 0.3 0.8
|
||||
// randomvel 20 magnitude/3
|
||||
// veladd magnitude
|
||||
// orgadd magnitude/10
|
||||
// spawnorg 4
|
||||
// gravity -400
|
||||
// scalefactor 0.8
|
||||
//}
|
||||
|
||||
|
||||
//this is apparently just a trail effect (palette index specified by netcode)
|
||||
r_part teq2_forcewall
|
||||
|
|
|
@ -3169,8 +3169,18 @@ retry:
|
|||
switch(st[i].op)
|
||||
{
|
||||
case OP_ADDRESS:
|
||||
if (st[i+1].op == OP_STOREP_V && st[i+1].b == st[i].c)
|
||||
{ //following stores a vector to this field.
|
||||
if (st[i].b+2 < pr_progs->numglobals)
|
||||
{ //vectors are usually 3 fields. if they're not then we're screwed.
|
||||
basictypetable[st[i].b+0] = ev_field;
|
||||
basictypetable[st[i].b+1] = ev_field;
|
||||
basictypetable[st[i].b+2] = ev_field;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//fallthrough
|
||||
case OP_LOAD_F:
|
||||
case OP_LOAD_V:
|
||||
case OP_LOAD_S:
|
||||
case OP_LOAD_ENT:
|
||||
case OP_LOAD_FLD:
|
||||
|
@ -3180,6 +3190,25 @@ retry:
|
|||
if (st[i].b < pr_progs->numglobals)
|
||||
basictypetable[st[i].b] = ev_field;
|
||||
break;
|
||||
case OP_LOAD_V:
|
||||
if (st[i].b+2 < pr_progs->numglobals)
|
||||
{ //vectors are usually 3 fields. if they're not then we're screwed.
|
||||
basictypetable[st[i].b+0] = ev_field;
|
||||
basictypetable[st[i].b+1] = ev_field;
|
||||
basictypetable[st[i].b+2] = ev_field;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < pr_progs->numglobaldefs; i++)
|
||||
{
|
||||
ddef16_t *gd = gd16+i;
|
||||
switch(gd->type & ~(DEF_SAVEGLOBAL|DEF_SHARED))
|
||||
{
|
||||
case ev_field: //depend on _y _z to mark those globals.
|
||||
basictypetable[gd->ofs] = ev_field;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1113,7 +1113,10 @@ int PDECL PR_ToggleBreakpoint(pubprogfuncs_t *ppf, char *filename, int linenum,
|
|||
//we need to use the function table in order to set breakpoints in the right file.
|
||||
for (f = pr_progstate[pn].functions, fl = 0; fl < pr_progstate[pn].progs->numfunctions; f++, fl++)
|
||||
{
|
||||
if (!stricmp(f->s_file+progfuncs->funcs.stringtable, filename))
|
||||
const char *fncfile = f->s_file+progfuncs->funcs.stringtable;
|
||||
if (fncfile[0] == '.' && fncfile[1] == '/')
|
||||
fncfile+=2;
|
||||
if (!stricmp(fncfile, filename))
|
||||
{
|
||||
for (i = f->first_statement; i < pr_progstate[pn].progs->numstatements; i++)
|
||||
{
|
||||
|
@ -1354,7 +1357,7 @@ static const char *lastfile = 0;
|
|||
if (debugaction == DEBUG_TRACE_NORESUME)
|
||||
continue;
|
||||
else if(debugaction == DEBUG_TRACE_ABORT)
|
||||
progfuncs->funcs.parms->Abort ("Debugger Abort");
|
||||
progfuncs->funcs.parms->Abort (fault?fault:"Debugger Abort");
|
||||
else if (debugaction == DEBUG_TRACE_OFF)
|
||||
{
|
||||
//if we're resuming, don't hit any lingering step-over triggers
|
||||
|
|
|
@ -511,6 +511,8 @@ model_t *QDECL SVPR_GetCModel(world_t *w, int modelindex)
|
|||
mod = sv.models[modelindex];
|
||||
if (mod && mod->loadstate != MLS_LOADED)
|
||||
{
|
||||
if (mod->loadstate == MLS_NOTLOADED)
|
||||
Mod_LoadModel(mod, MLV_SILENT);
|
||||
if (mod->loadstate == MLS_LOADING)
|
||||
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
|
||||
if (mod->loadstate != MLS_LOADED)
|
||||
|
@ -1681,18 +1683,6 @@ void PR_SpawnInitialEntities(const char *file)
|
|||
sv.world.edict_size = 0;
|
||||
}
|
||||
|
||||
static qofs_t PR_ReadBytesString(char *str)
|
||||
{
|
||||
size_t u = strtoul(str, &str, 0);
|
||||
if (*str == 'g')
|
||||
u *= 1024*1024*1024;
|
||||
if (*str == 'm')
|
||||
u *= 1024*1024;
|
||||
if (*str == 'k')
|
||||
u *= 1024;
|
||||
return u;
|
||||
}
|
||||
|
||||
void SV_RegisterH2CustomTents(void);
|
||||
void Q_InitProgs(void)
|
||||
{
|
||||
|
@ -3479,38 +3469,6 @@ static void QCBUILTIN PF_ss_LocalSound(pubprogfuncs_t *prinst, struct globalvars
|
|||
#define PF_ss_LocalSound PF_Fixme
|
||||
#endif
|
||||
|
||||
unsigned int FTEToDPContents(unsigned int contents)
|
||||
{
|
||||
unsigned int r = 0;
|
||||
if (contents & FTECONTENTS_SOLID)
|
||||
r |= DPCONTENTS_SOLID;
|
||||
if (contents & FTECONTENTS_WATER)
|
||||
r |= DPCONTENTS_WATER;
|
||||
if (contents & FTECONTENTS_SLIME)
|
||||
r |= DPCONTENTS_SLIME;
|
||||
if (contents & FTECONTENTS_LAVA)
|
||||
r |= DPCONTENTS_LAVA;
|
||||
if (contents & FTECONTENTS_SKY)
|
||||
r |= DPCONTENTS_SKY;
|
||||
if (contents & FTECONTENTS_BODY)
|
||||
r |= DPCONTENTS_BODY;
|
||||
if (contents & FTECONTENTS_CORPSE)
|
||||
r |= DPCONTENTS_CORPSE;
|
||||
if (contents & Q3CONTENTS_NODROP)
|
||||
r |= DPCONTENTS_NODROP;
|
||||
if (contents & FTECONTENTS_PLAYERCLIP)
|
||||
r |= DPCONTENTS_PLAYERCLIP;
|
||||
if (contents & FTECONTENTS_MONSTERCLIP)
|
||||
r |= DPCONTENTS_MONSTERCLIP;
|
||||
if (contents & Q3CONTENTS_DONOTENTER)
|
||||
r |= DPCONTENTS_DONOTENTER;
|
||||
if (contents & Q3CONTENTS_BOTCLIP)
|
||||
r |= DPCONTENTS_BOTCLIP;
|
||||
// if (contents & FTECONTENTS_OPAQUE)
|
||||
// r |= DPCONTENTS_OPAQUE;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void set_trace_globals(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, trace_t *trace)
|
||||
{
|
||||
pr_global_struct->trace_allsolid = trace->allsolid;
|
||||
|
@ -5979,16 +5937,21 @@ static void QCBUILTIN PF_infokey_f (pubprogfuncs_t *prinst, struct globalvars_s
|
|||
G_FLOAT(OFS_RETURN) = atof(value);
|
||||
}
|
||||
|
||||
static void QCBUILTIN PF_sv_serverkey (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
static void QCBUILTIN PF_sv_serverkeystring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
char *value;
|
||||
const char *key;
|
||||
|
||||
key = PR_GetStringOfs(prinst, OFS_PARM1);
|
||||
value = Info_ValueForKey (svs.info, key);
|
||||
G_INT(OFS_RETURN) = PR_TempString(prinst, value);
|
||||
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
const char *value = Info_ValueForKey (svs.info, key);
|
||||
G_INT(OFS_RETURN) = *value?PR_TempString(prinst, value):0;
|
||||
}
|
||||
static void QCBUILTIN PF_sv_serverkeyfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
const char *value = Info_ValueForKey (svs.info, key);
|
||||
if (*value)
|
||||
G_FLOAT(OFS_RETURN) = strtod(value, NULL);
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = (prinst->callargc>=2)?G_FLOAT(OFS_PARM1):0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
|
@ -7117,8 +7080,8 @@ const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned
|
|||
case SCP_NETQUAKE: bp = "nq"; break;
|
||||
case SCP_BJP3: bp = "bjp3"; break;
|
||||
case SCP_FITZ666: bp = "fitz666"; break;
|
||||
case SCP_DARKPLACES6: bp = "dp6"; break;
|
||||
case SCP_DARKPLACES7: bp = "dp7"; break;
|
||||
case SCP_DARKPLACES6: bp = "dpp6"; break;
|
||||
case SCP_DARKPLACES7: bp = "dpp7"; break;
|
||||
}
|
||||
Info_SetValueForKey(clfeatures, "basicprotocol", bp, sizeof(clfeatures));
|
||||
Info_SetValueForKey(clfeatures, "guid", guid, sizeof(clfeatures));
|
||||
|
@ -9168,14 +9131,14 @@ static void QCBUILTIN PF_setcolors (pubprogfuncs_t *prinst, struct globalvars_s
|
|||
client->edict->v->team = (i & 15) + 1;
|
||||
|
||||
sprintf(number, "%i", i>>4);
|
||||
if (!strcmp(number, Info_ValueForKey(client->userinfo, "topcolor")))
|
||||
if (strcmp(number, Info_ValueForKey(client->userinfo, "topcolor")))
|
||||
{
|
||||
Info_SetValueForKey(client->userinfo, "topcolor", number, sizeof(client->userinfo));
|
||||
key = "topcolor";
|
||||
}
|
||||
|
||||
sprintf(number, "%i", i&15);
|
||||
if (!strcmp(number, Info_ValueForKey(client->userinfo, "bottomcolor")))
|
||||
if (strcmp(number, Info_ValueForKey(client->userinfo, "bottomcolor")))
|
||||
{
|
||||
Info_SetValueForKey(client->userinfo, "bottomcolor", number, sizeof(client->userinfo));
|
||||
key = key?"*bothcolours":"bottomcolor";
|
||||
|
@ -9464,9 +9427,7 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars
|
|||
pmove_mins[i] = pmove.origin[i] - 256;
|
||||
pmove_maxs[i] = pmove.origin[i] + 256;
|
||||
}
|
||||
AddLinksToPmove(ent, sv.world.areanodes);
|
||||
// AddAllEntsToPmove();
|
||||
AddLinksToPmove_Force ( ent, &sv.world.portallist );
|
||||
AddAllLinksToPmove(&sv.world, (wedict_t*)ent);
|
||||
|
||||
SV_PreRunCmd();
|
||||
|
||||
|
@ -9841,6 +9802,11 @@ static void QCBUILTIN PF_setpause(pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
G_FLOAT(OFS_RETURN) = !!(sv.paused&PAUSE_EXPLICIT);
|
||||
if (sv.paused != pause)
|
||||
{
|
||||
if (pause&PAUSE_EXPLICIT)
|
||||
SV_BroadcastTPrintf (PRINT_HIGH, "game paused\n");
|
||||
else
|
||||
SV_BroadcastTPrintf (PRINT_HIGH, "game unpaused\n");
|
||||
|
||||
sv.paused = pause;
|
||||
sv.pausedstart = Sys_DoubleTime();
|
||||
}
|
||||
|
@ -9976,7 +9942,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
|
|||
{"remove", PF_Remove, 15, 15, 15, 0, D("void(entity e)", "Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After two seconds, the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid.")},
|
||||
{"traceline", PF_svtraceline, 16, 16, 16, 0, D("void(vector v1, vector v2, float flags, entity ent)", "Traces a thin line through the world from v1 towards v2.\nWill not collide with ent, ent.owner, or any entity who's owner field refers to ent.\nThe passed entity will also be used to determine whether to use a capsule trace, the contents that the trace should impact, and a couple of other extra fields that define the trace.\nThere are no side effects beyond the trace_* globals being written.\nflags&MOVE_NOMONSTERS will not impact on non-bsp entities.\nflags&MOVE_MISSILE will impact with increased size.\nflags&MOVE_HITMODEL will impact upon model meshes, instead of their bounding boxes.\nflags&MOVE_TRIGGERS will also stop on triggers\nflags&MOVE_EVERYTHING will stop if it hits anything, even non-solid entities.\nflags&MOVE_LAGGED will backdate entity positions for the purposes of this builtin according to the indicated player ent's latency, to provide lag compensation.")},
|
||||
{"checkclient", PF_checkclient, 17, 17, 17, 0, D("entity()", "Returns one of the player entities. The returned player will change periodically.")},
|
||||
{"find", PF_FindString, 18, 18, 18, 0, D("entity(entity start, .string fld, string match)", "Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more.")},
|
||||
{"find", PF_FindString, 18, 18, 18, 0, D("entity(entity start, .string fld, string match)", "Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more.\nIf you have many many entities then you may find that hashtables will give more performance (but requires extra upkeep).")},
|
||||
{"precache_sound", PF_precache_sound, 19, 19, 19, 0, D("string(string s)", "Precaches a sound, making it known to clients and loading it from disk. This builtin (strongly) should be called during spawn functions. This builtin must be called for the sound before the sound builtin is called, or it might not even be heard.")},
|
||||
{"precache_model", PF_precache_model, 20, 20, 20, 0, D("string(string s)", "Precaches a model, making it known to clients and loading it from disk if it has a .bsp extension. This builtin (strongly) should be called during spawn functions. This must be called for each model name before setmodel may use that model name.\nModelindicies precached in SSQC will always be positive. CSQC precaches will be negative if they are not also on the server.")},
|
||||
{"stuffcmd", PF_stuffcmd, 21, 21, 21, 0, D("void(entity client, string s)", "Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \\n.\nThis builtin is generally considered evil.")},
|
||||
|
@ -10305,7 +10271,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
|
|||
|
||||
{"checkpvs", PF_checkpvs, 0, 0, 0, 240, "float(vector viewpos, entity entity)"},
|
||||
{"matchclientname", PF_matchclient, 0, 0, 0, 241, "entity(string match, optional float matchnum)"},
|
||||
{"sendpacket", PF_SendPacket, 0, 0, 0, 242, "void(string dest, string content)"},// (FTE_QC_SENDPACKET)
|
||||
{"sendpacket", PF_SendPacket, 0, 0, 0, 242, "void(string destaddress, string content)"},// (FTE_QC_SENDPACKET)
|
||||
|
||||
// {"bulleten", PF_bulleten, 0, 0, 0, 243}, (removed builtin)
|
||||
|
||||
|
@ -10484,6 +10450,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
|
|||
|
||||
{"runstandardplayerphysics",PF_runclientphys,0,0,0, 347, D("void(entity ent)", "Perform the engine's standard player movement prediction upon the given entity using the input_* globals to describe movement.")},
|
||||
{"getplayerkeyvalue", PF_Fixme,0, 0, 0, 348, D("string(float playernum, string keyname)", "Look up a player's userinfo, to discover things like their name, topcolor, bottomcolor, skin, team, *ver.\nAlso includes scoreboard info like frags, ping, pl, userid, entertime, as well as voipspeaking and voiploudness.")},// (EXT_CSQC)
|
||||
{"getplayerkeyfloat", PF_Fixme,0, 0, 0, 0, D("float(float playernum, string keyname, optional float assumevalue)", "Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings.")},
|
||||
|
||||
{"isdemo", PF_Fixme, 0, 0, 0, 349, D("float()", "Returns if the client is currently playing a demo or not")},// (EXT_CSQC)
|
||||
{"isserver", PF_Fixme, 0, 0, 0, 350, D("float()", "Returns if the client is acting as the server (aka: listen server)")},//(EXT_CSQC)
|
||||
|
@ -10491,10 +10458,12 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
|
|||
{"setup_reverb", PF_Fixme, 0, 0, 0, 0, D("typedef struct {\n\tfloat flDensity;\n\tfloat flDiffusion;\n\tfloat flGain;\n\tfloat flGainHF;\n\tfloat flGainLF;\n\tfloat flDecayTime;\n\tfloat flDecayHFRatio;\n\tfloat flDecayLFRatio;\n\tfloat flReflectionsGain;\n\tfloat flReflectionsDelay;\n\tvector flReflectionsPan;\n\tfloat flLateReverbGain;\n\tfloat flLateReverbDelay;\n\tvector flLateReverbPan;\n\tfloat flEchoTime;\n\tfloat flEchoDepth;\n\tfloat flModulationTime;\n\tfloat flModulationDepth;\n\tfloat flAirAbsorptionGainHF;\n\tfloat flHFReference;\n\tfloat flLFReference;\n\tfloat flRoomRolloffFactor;\n\tint iDecayHFLimit;\n} reverbinfo_t;\nvoid(float reverbslot, reverbinfo_t *reverbinfo, int sizeofreverinfo_t)", "Reconfigures a reverb slot for weird effects. Slot 0 is reserved for no effects. Slot 1 is reserved for underwater effects. Reserved slots will be reinitialised on snd_restart, but can otherwise be changed. These reverb slots can be activated with SetListener. Note that reverb will currently only work when using OpenAL.")},
|
||||
{"registercommand", PF_Fixme, 0, 0, 0, 352, D("void(string cmdname)", "Register the given console command, for easy console use.\nConsole commands that are later used will invoke CSQC_ConsoleCommand.")},//(EXT_CSQC)
|
||||
{"wasfreed", PF_WasFreed,0, 0, 0, 353, D("float(entity ent)", "Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust.")},//(EXT_CSQC) (should be availabe on server too)
|
||||
{"serverkey", PF_sv_serverkey,0, 0, 0, 354, D("string(string key)", "Look up a key in the server's public serverinfo string")},//
|
||||
{"serverkey", PF_sv_serverkeystring,0,0, 0, 354, D("string(string key)", "Look up a key in the server's public serverinfo string")},//
|
||||
{"serverkeyfloat", PF_sv_serverkeyfloat,0,0, 0, 0, D("float(string key, optional float assumevalue)", "Version of serverkey that returns the value as a float (which avoids tempstrings).")},//
|
||||
{"getentitytoken", PF_Fixme, 0, 0, 0, 355, D("string(optional string resetstring)", "Grab the next token in the map's entity lump.\nIf resetstring is not specified, the next token will be returned with no other sideeffects.\nIf empty, will reset from the map before returning the first token, probably {.\nIf not empty, will tokenize from that string instead.\nAlways returns tempstrings.")},//;
|
||||
{"findfont", PF_Fixme, 0, 0, 0, 356, D("float(string s)", "Looks up a named font slot. Matches the actual font name as a last resort.")},//;
|
||||
{"loadfont", PF_Fixme, 0, 0, 0, 357, D("float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset)", "too convoluted for me to even try to explain correct usage. Try drawfont = loadfont(\"\", \"cour\", \"16\", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows..")},
|
||||
//358
|
||||
{"sendevent", PF_Fixme, 0, 0, 0, 359, D("void(string evname, string evargs, ...)", "Invoke Cmd_evname_evargs in ssqc. evargs must be a string of initials refering to the types of the arguments to pass. v=vector, e=entity(.entnum field is sent), f=float, i=int. 6 arguments max - you can get more if you pack your floats into vectors.")},// (EXT_CSQC_1)
|
||||
|
||||
{"readbyte", PF_Fixme, 0, 0, 0, 360, "float()"},// (EXT_CSQC)
|
||||
|
@ -11561,7 +11530,8 @@ void PR_DumpPlatform_f(void)
|
|||
{"CSQC_RendererRestarted", "void(string rendererdescription)", CS, "Called by the engine after the video was restarted. This serves to notify the CSQC that any render targets that it may have cached were purged, and will need to be regenerated."},
|
||||
{"CSQC_ConsoleCommand", "float(string cmd)", CS, "Called if the user uses any console command registed via registercommand."},
|
||||
{"CSQC_ConsoleLink", "float(string text, string info)", CS, "Called if the user clicks a ^[text\\infokey\\infovalue^] link. Use infoget to read/check each supported key. Return true if you wish the engine to not attempt to handle the link itself.\nWARNING: link text can potentially come from other players, so be careful about what you allow to be changed."},
|
||||
{"CSQC_Ent_Update", "void(float isnew)", CS},
|
||||
{"CSQC_Ent_Spawn", "void(float entnum)", CS, "Clumsily defined function for compat with DP. Should call spawn, set that ent's entnum field, and return the entity inside the 'self' global which will then be used for fllowing Ent_Updates. MUST NOT PARSE ANY NETWORK DATA (which makes it kinda useless)."},
|
||||
{"CSQC_Ent_Update", "void(float isnew)", CS, "Parses the data sent by ssqc's various SendEntity functions (must use the exact same reads as the ssqc used writes - to debug this rule more easily, you may wish to use sv_csqcdebug). 'self' provides context between frames, and self.entnum should normally report which ssqc entity . Be aware that interpolation will need to happen separately."},
|
||||
{"CSQC_Ent_Remove", "void()", CS},
|
||||
{"CSQC_Event_Sound", "float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod, float flags"/*", float timeofs*/")", CS},
|
||||
// {"CSQC_ServerSound", "//void()", CS},
|
||||
|
|
|
@ -424,6 +424,11 @@ comextqcfields
|
|||
} comentvars_t;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
#define AREAGRIDPERENT 16
|
||||
#endif
|
||||
|
||||
#ifdef USERBE
|
||||
typedef struct
|
||||
{
|
||||
|
|
|
@ -75,7 +75,12 @@ typedef struct edict_s
|
|||
/*qc lib doesn't care about the rest*/
|
||||
|
||||
/*these are shared with csqc*/
|
||||
#ifdef USEAREAGRID
|
||||
areagridlink_t gridareas[AREAGRIDPERENT]; //on overflow, use the inefficient overflow list.
|
||||
size_t gridareasequence; //used to avoid iterrating the same ent twice.
|
||||
#else
|
||||
link_t area;
|
||||
#endif
|
||||
pvscache_t pvsinfo;
|
||||
int lastruntime;
|
||||
int solidsize;
|
||||
|
|
|
@ -864,7 +864,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
|
|||
SV_SpawnParmsToQC(host_client);
|
||||
pr_global_struct->time = sv.world.physicstime;
|
||||
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, ent);
|
||||
ent->area.next = ent->area.prev = NULL;
|
||||
World_UnlinkEdict((wedict_t*)ent);
|
||||
G_FLOAT(OFS_PARM0) = sv.time-host_client->spawninfotime;
|
||||
PR_ExecuteProgram(svprogfuncs, eval->function);
|
||||
|
||||
|
|
|
@ -489,6 +489,10 @@ typedef struct client_s
|
|||
// extracted from userinfo
|
||||
char guid[64]; /*+2 for split+pad*/
|
||||
int messagelevel; // for filtering printed messages
|
||||
#ifndef NOLEGACY
|
||||
float *dp_ping;
|
||||
float *dp_pl;
|
||||
#endif
|
||||
|
||||
// the datagram is written to after every frame, but only cleared
|
||||
// when it is sent out to the client. overflow is tolerated.
|
||||
|
@ -586,7 +590,7 @@ typedef struct client_s
|
|||
int chokecount;
|
||||
qboolean waschoked;
|
||||
int delta_sequence; // -1 = no compression
|
||||
int last_sequence;
|
||||
int last_sequence; //last inputframe sequence received
|
||||
netchan_t netchan;
|
||||
qboolean isindependant;
|
||||
|
||||
|
@ -655,7 +659,7 @@ typedef struct client_s
|
|||
unsigned int lastruncmd; //for non-qw physics. timestamp they were last run, so switching between physics modes isn't a (significant) cheat
|
||||
//speed cheat testing
|
||||
#define NEWSPEEDCHEATPROT
|
||||
int msecs;
|
||||
float msecs;
|
||||
#ifndef NEWSPEEDCHEATPROT
|
||||
int msec_cheating;
|
||||
float last_check;
|
||||
|
@ -1168,6 +1172,7 @@ typedef struct pubsubserver_s
|
|||
int transferingplayers;
|
||||
netadr_t addrv4;
|
||||
netadr_t addrv6;
|
||||
char printtext[4096]; //to split it into lines.
|
||||
} pubsubserver_t;
|
||||
extern qboolean isClusterSlave;
|
||||
void SSV_UpdateAddresses(void);
|
||||
|
@ -1587,8 +1592,13 @@ void SV_CheckTimer(void);
|
|||
void SV_LogPlayer(client_t *cl, char *msg);
|
||||
|
||||
extern vec3_t pmove_mins, pmove_maxs; //abs min/max extents
|
||||
void AddLinksToPmove ( edict_t *player, areanode_t *node );
|
||||
void AddLinksToPmove_Force ( edict_t *player, areanode_t *node );
|
||||
#ifdef USEAREAGRID
|
||||
void AddAllLinksToPmove (world_t *w, wedict_t *player);
|
||||
#else
|
||||
void AddLinksToPmove (world_t *w, wedict_t *player, areanode_t *node);
|
||||
void AddLinksToPmove_Force (world_t *w, wedict_t *player, areanode_t *node);
|
||||
#define AddAllLinksToPmove(w,p) do{AddLinksToPmove(w,p,(w)->areanodes);AddLinksToPmove_Force(w,p,&(w)->portallist);}while(0)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HLSERVER
|
||||
|
|
|
@ -1984,7 +1984,7 @@ static void SV_Status_f (void)
|
|||
else
|
||||
{
|
||||
#define COLUMNS C_FRAGS C_USERID C_ADDRESS C_NAME C_RATE C_PING C_DROP C_DLP C_DLS C_PROT C_ADDRESS2
|
||||
#define C_FRAGS COLUMN(0, "frags", Con_Printf("%5i ", (int)cl->old_frags))
|
||||
#define C_FRAGS COLUMN(0, "frags", if (cl->spectator==1)Con_Printf("%-5s ", "spec"); else Con_Printf("%5i ", (int)cl->old_frags))
|
||||
#define C_USERID COLUMN(1, "userid", Con_Printf("%6i ", (int)cl->userid))
|
||||
#define C_ADDRESS COLUMN(2, "address ", Con_Printf("%-16.16s", s))
|
||||
#define C_NAME COLUMN(3, "name ", Con_Printf("%-16.16s", cl->name))
|
||||
|
@ -2052,24 +2052,17 @@ static void SV_Status_f (void)
|
|||
case SCP_BAD:
|
||||
p = "";
|
||||
break;
|
||||
case SCP_QUAKEWORLD:
|
||||
if (cl->spectator)
|
||||
p = "s";
|
||||
else if (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
|
||||
p = "fte";
|
||||
else
|
||||
p = "qw";
|
||||
break;
|
||||
case SCP_QUAKEWORLD: p = (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)?"fteq":"qw"; break;
|
||||
case SCP_QUAKE2: p = "q2"; break;
|
||||
case SCP_QUAKE3: p = "q3"; break;
|
||||
case SCP_NETQUAKE: p = "nq"; break;
|
||||
case SCP_BJP3: p = "bjp3"; break;
|
||||
case SCP_FITZ666: p = "fitz"; break;
|
||||
case SCP_DARKPLACES6: p = "dp6"; break;
|
||||
case SCP_DARKPLACES7: p = "dp7"; break;
|
||||
case SCP_NETQUAKE: p = (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)?"ften":"nq"; break;
|
||||
case SCP_BJP3: p = (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)?"ften":"bjp3"; break;
|
||||
case SCP_FITZ666: p = (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)?"ften":"fitz"; break;
|
||||
case SCP_DARKPLACES6: p = "dpp6"; break;
|
||||
case SCP_DARKPLACES7: p = "dpp7"; break;
|
||||
}
|
||||
if (cl->state == cs_connected && cl->protocol>=SCP_NETQUAKE)
|
||||
p = "nq";
|
||||
p = "nq"; //not actually known yet.
|
||||
else if (cl->state == cs_zombie || cl->state == cs_loadzombie)
|
||||
p = "zom";
|
||||
|
||||
|
@ -3008,6 +3001,11 @@ void SV_InitOperatorCommands (void)
|
|||
Cmd_AddCommand ("sv", SV_SendGameCommand_f);
|
||||
Cmd_AddCommand ("mod", SV_SendGameCommand_f);
|
||||
|
||||
#ifdef SUBSERVERS
|
||||
Cmd_AddCommand ("ssv", MSV_SubServerCommand_f);
|
||||
Cmd_AddCommand ("ssv_all", MSV_SubServerCommand_f);
|
||||
Cmd_AddCommandAD ("mapcluster", MSV_MapCluster_f, SV_Map_c, "Sets this server up as a cluster-server gateway. Additional processes will be used to host individual maps. If an argument is given then that will be the name of the map that new clients will initially be directed to. This can also be used for single-player to off-load nearly all server functions - use the 'ssv' command to direct each subserver.");
|
||||
#endif
|
||||
Cmd_AddCommand ("killserver", SV_KillServer_f);
|
||||
Cmd_AddCommandD ("precaches", SV_PrecacheList_f, "Displays a list of current server precaches.");
|
||||
Cmd_AddCommandAD ("map", SV_Map_f, SV_Map_c, "Changes map. If a second argument is specified then that is normally the name of the initial start spot.");
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
//":dm4" finds any server running dm4. starts a new one if none are running dm4.
|
||||
//"dm4" is ambiguous, in the case of a map beginning with a number (bah). don't use.
|
||||
|
||||
//FIXME: nq protocols not supported.
|
||||
//FIXME: deadlocks when both gw and ss both fill their pipe buffers.
|
||||
//FIXME: no networking for remote nodes.
|
||||
|
||||
#ifdef SUBSERVERS
|
||||
|
||||
#ifdef SQL
|
||||
|
@ -384,6 +388,23 @@ void MSV_SubServerCommand_f(void)
|
|||
MSV_InstructSlave(id, &buf);
|
||||
}
|
||||
|
||||
static void MSV_PrintFromSubServer(pubsubserver_t *s, const char *newtext)
|
||||
{
|
||||
char *nl;
|
||||
Q_strncatz(s->printtext, newtext, sizeof(s->printtext));
|
||||
while((nl = strchr(s->printtext, '\n')))
|
||||
{ //FIXME: handle overflows.
|
||||
*nl++ = 0;
|
||||
Con_Printf("^6%i(%s)^7: %s\n", s->id, s->name, s->printtext);
|
||||
memmove(s->printtext, nl, strlen(nl)+1);
|
||||
}
|
||||
if (strlen(s->printtext) > sizeof(s->printtext)/2)
|
||||
{
|
||||
Con_Printf("^6%i(%s)^7: %s\n", s->id, s->name, s->printtext);
|
||||
*s->printtext = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MSV_ReadFromSubServer(pubsubserver_t *s)
|
||||
{
|
||||
sizebuf_t send;
|
||||
|
@ -402,7 +423,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
|
|||
Sys_Error("Corrupt message (%i) from SubServer %i:%s", c, s->id, s->name);
|
||||
break;
|
||||
case ccmd_print:
|
||||
Con_Printf("^6%i(%s)^7: %s", s->id, s->name, MSG_ReadString());
|
||||
MSV_PrintFromSubServer(s, MSG_ReadString());
|
||||
break;
|
||||
case ccmd_saveplayer:
|
||||
{
|
||||
|
@ -779,7 +800,6 @@ void SSV_ReadFromControlServer(void)
|
|||
Q_strncpyz(cl->guid, clguid, sizeof(cl->guid));
|
||||
Q_strncpyz(cl->namebuf, plname, sizeof(cl->namebuf));
|
||||
cl->name = cl->namebuf;
|
||||
sv.spawned_client_slots++;
|
||||
memset(&cl->netchan, 0, sizeof(cl->netchan));
|
||||
SV_GetNewSpawnParms(cl);
|
||||
}
|
||||
|
@ -787,7 +807,7 @@ void SSV_ReadFromControlServer(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
Con_Printf("%s: server full!\n", sv.modelname);
|
||||
Con_Printf("%s: server full!\n", svs.name);
|
||||
}
|
||||
|
||||
j = MSG_ReadByte();
|
||||
|
@ -969,7 +989,7 @@ void SSV_UpdateAddresses(void)
|
|||
send.cursize = 2;
|
||||
MSG_WriteByte(&send, ccmd_serveraddress);
|
||||
|
||||
MSG_WriteString(&send, sv.modelname);
|
||||
MSG_WriteString(&send, svs.name);
|
||||
for (i = 0; i < count; i++)
|
||||
MSG_WriteString(&send, NET_AdrToString(buf, sizeof(buf), &addr[i]));
|
||||
MSG_WriteByte(&send, 0);
|
||||
|
|
|
@ -996,7 +996,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
|
|||
|
||||
if (FS_FLocateFile(sv.modelname,FSLF_IFFOUND, &loc) && FS_GetLocMTime(&loc, &filetime))
|
||||
{
|
||||
if (filetime > sv.world.worldmodel->mtime)
|
||||
if (filetime > sv.world.worldmodel->mtime && sv.world.worldmodel->mtime)
|
||||
{
|
||||
COM_WorkerFullSync(); //sync all the workers, just in case.
|
||||
Mod_PurgeModel(sv.world.worldmodel, MP_RESET); //nuke it now
|
||||
|
@ -1668,7 +1668,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
|
|||
SV_SpawnParmsToQC(host_client);
|
||||
SV_SetUpClientEdict(host_client, sv_player);
|
||||
#ifndef NOLEGACY
|
||||
sv_player->xv->clientcolors = atoi(Info_ValueForKey(host_client->userinfo, "topcolor"))*16 + atoi(Info_ValueForKey(host_client->userinfo, "bottomcolor"));
|
||||
sv_player->xv->clientcolors = host_client->playercolor;
|
||||
#endif
|
||||
|
||||
// call the spawn function
|
||||
|
|
|
@ -2663,9 +2663,9 @@ client_t *SVC_DirectConnect(void)
|
|||
protocol = SCP_FITZ666;
|
||||
else if (!strcmp(sv_protocol_nq.string, "bjp") || !strcmp(sv_protocol_nq.string, "bjp3"))
|
||||
protocol = SCP_BJP3;
|
||||
else if (!strcmp(sv_protocol_nq.string, "dp6"))
|
||||
else if (!strcmp(sv_protocol_nq.string, "dpp6") || !strcmp(sv_protocol_nq.string, "dp6"))
|
||||
protocol = SCP_DARKPLACES6;
|
||||
else if (!strcmp(sv_protocol_nq.string, "dp7"))
|
||||
else if (!strcmp(sv_protocol_nq.string, "dpp7") || !strcmp(sv_protocol_nq.string, "dp7"))
|
||||
protocol = SCP_DARKPLACES7;
|
||||
else if (!strcmp(sv_protocol_nq.string, "id") || !strcmp(sv_protocol_nq.string, "vanilla"))
|
||||
protocol = SCP_NETQUAKE;
|
||||
|
@ -5147,12 +5147,6 @@ void SV_InitLocal (void)
|
|||
|
||||
Cmd_AddCommand ("sv_impulse", SV_Impulse_f);
|
||||
|
||||
#ifdef SUBSERVERS
|
||||
Cmd_AddCommand ("ssv", MSV_SubServerCommand_f);
|
||||
Cmd_AddCommand ("ssv_all", MSV_SubServerCommand_f);
|
||||
Cmd_AddCommand ("mapcluster", MSV_MapCluster_f);
|
||||
#endif
|
||||
|
||||
Cmd_AddCommand ("openroute", SV_OpenRoute_f);
|
||||
|
||||
#ifndef NOBUILTINMENUS
|
||||
|
@ -5347,7 +5341,9 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
|
|||
newname[0] = 0;
|
||||
|
||||
deleetstring(basic, newname);
|
||||
if ((!basic[0] && cl->protocol != SCP_BAD) || strstr(basic, "console"))
|
||||
if (cl->protocol != SCP_BAD)
|
||||
{ //don't bother validating bot names. The gamecode is expected to not be stupid.
|
||||
if (!basic[0] || strstr(basic, "console"))
|
||||
strcpy(newname, "unnamed");
|
||||
|
||||
// check to see if another user by the same name exists
|
||||
|
@ -5381,6 +5377,7 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
|
|||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cl->drop && strncmp(newname, cl->name, sizeof(cl->namebuf)-1))
|
||||
{
|
||||
|
|
|
@ -813,11 +813,19 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
|
|||
continue;
|
||||
}
|
||||
|
||||
//these pushes are contents brushes, and are not solid. water cannot crush. the player just enters the water.
|
||||
//some pushers are contents brushes, and are not solid. water cannot crush. the player just enters the water.
|
||||
//but, the player will be moved along with the water if possible.
|
||||
if (pusher->v->skin < 0)
|
||||
continue;
|
||||
|
||||
if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
|
||||
{ // corpse
|
||||
check->v->mins[0] = check->v->mins[1] = 0;
|
||||
VectorCopy (check->v->mins, check->v->maxs);
|
||||
World_LinkEdict (w, check, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Con_Printf("Pusher hit %s\n", PR_GetString(w->progs, check->v->classname));
|
||||
if (pusher->v->blocked)
|
||||
{
|
||||
|
@ -846,7 +854,7 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
|
|||
//FIXME: is there a better way to handle this?
|
||||
// see if anything we moved has touched a trigger
|
||||
for (p=pushed_p-1 ; p>=pushed ; p--)
|
||||
World_TouchLinks (w, p->ent, w->areanodes);
|
||||
World_TouchAllLinks (w, p->ent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1329,6 +1337,7 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent)
|
|||
|
||||
// add gravity
|
||||
if (ent->v->movetype != MOVETYPE_FLY
|
||||
&& ent->v->movetype != MOVETYPE_FLY_WORLDONLY
|
||||
&& ent->v->movetype != MOVETYPE_FLYMISSILE
|
||||
&& ent->v->movetype != MOVETYPE_BOUNCEMISSILE
|
||||
&& ent->v->movetype != MOVETYPE_H2SWIM)
|
||||
|
@ -2190,7 +2199,6 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent)
|
|||
if (!(ent->entnum > 0 && ent->entnum <= sv.allocated_client_slots) && w == &sv.world)
|
||||
World_LinkEdict (w, ent, true);
|
||||
#endif
|
||||
|
||||
break;
|
||||
#ifdef USERBE
|
||||
case MOVETYPE_PHYSICS:
|
||||
|
|
|
@ -2020,8 +2020,6 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
|
|||
if (bits & FITZSU_WEAPONFRAME2) MSG_WriteByte (msg, (int)ent->v->weaponframe >> 8);
|
||||
if (bits & FITZSU_WEAPONALPHA) MSG_WriteByte (msg, ent->xv->alpha*255);
|
||||
}
|
||||
|
||||
// }
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2726,7 +2724,13 @@ qboolean SV_SendClientDatagram (client_t *client)
|
|||
|
||||
// send the datagram
|
||||
sentbytes = Netchan_Transmit (&client->netchan, msg.cursize, buf, SV_RateForClient(client));
|
||||
if (ISQWCLIENT(client) || ISNQCLIENT(client))
|
||||
if (ISNQCLIENT(client))
|
||||
{
|
||||
client_frame_t *frame = &client->frameunion.frames[client->netchan.outgoing_sequence & UPDATE_MASK];
|
||||
frame->packetsizeout += sentbytes;
|
||||
frame->senttime = realtime;
|
||||
}
|
||||
else if (ISQWCLIENT(client))
|
||||
{
|
||||
client_frame_t *frame = &client->frameunion.frames[client->netchan.outgoing_sequence & UPDATE_MASK];
|
||||
frame->packetsizeout += sentbytes;
|
||||
|
@ -2886,6 +2890,11 @@ void SV_UpdateToReliableMessages (void)
|
|||
SV_BroadcastUserinfoChange(host_client, true, "*bothcolours", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (host_client->dp_ping)
|
||||
*host_client->dp_ping = SV_CalcPing (host_client, false);
|
||||
if (host_client->dp_pl)
|
||||
*host_client->dp_pl = host_client->lossage;
|
||||
#endif
|
||||
|
||||
name = PR_GetString(svprogfuncs, host_client->edict->v->netname);
|
||||
|
|
|
@ -55,7 +55,7 @@ cvar_t sv_cheatspeedchecktime = CVARD("sv_cheatspeedchecktime", "30", "The inter
|
|||
#endif
|
||||
cvar_t sv_playermodelchecks = CVAR("sv_playermodelchecks", "0");
|
||||
cvar_t sv_ping_ignorepl = CVARD("sv_ping_ignorepl", "0", "If 1, ping times reported for players will ignore the effects of packetloss on ping times. 0 is slightly more honest, but less useful for connection diagnosis.");
|
||||
cvar_t sv_protocol_nq = CVARD("sv_protocol_nq", "", "Specifies the default protocol to use for new NQ clients. Supported values are\n0 = autodetect\n15 = vanilla\n666 = fitzquake\n999 = rmq protocol\nThe sv_bigcoords cvar forces upgrades as required.");
|
||||
cvar_t sv_protocol_nq = CVARD("sv_protocol_nq", "", "Specifies the default protocol to use for new NQ clients. This is only relevent for clients that do not report their supported protocols. Supported values are\n0 = autodetect\n15 = vanilla\n666 = fitzquake\n999 = rmq protocol\nThe sv_bigcoords cvar forces upgrades as required.");
|
||||
|
||||
cvar_t sv_minpitch = CVARAFD("minpitch", "", "sv_minpitch", CVAR_SERVERINFO, "Assumed to be -70");
|
||||
cvar_t sv_maxpitch = CVARAFD("maxpitch", "", "sv_maxpitch", CVAR_SERVERINFO, "Assumed to be 80");
|
||||
|
@ -464,6 +464,7 @@ void SVNQ_New_f (void)
|
|||
extern cvar_t sv_listen_nq;
|
||||
const char *gamedir;
|
||||
unsigned int modelcount, soundcount;
|
||||
extern cvar_t allow_download;
|
||||
|
||||
host_client->prespawn_stage = PRESPAWN_INVALID;
|
||||
host_client->prespawn_idx = 0;
|
||||
|
@ -608,17 +609,19 @@ void SVNQ_New_f (void)
|
|||
SV_LogPlayer(host_client, "new (DP6)");
|
||||
protmain = PROTOCOL_VERSION_DP6;
|
||||
protext1 &= ~PEXT_FLOATCOORDS; //always enabled, try not to break things
|
||||
protext2 = host_client->fteprotocolextensions2 = host_client->fteprotocolextensions2 & ~(PEXT2_PREDINFO|PEXT2_REPLACEMENTDELTAS); //always disabled. kinda interferes with expectations.
|
||||
protoname = "DPP6";
|
||||
break;
|
||||
case SCP_DARKPLACES7:
|
||||
SV_LogPlayer(host_client, "new (DP7)");
|
||||
protmain = PROTOCOL_VERSION_DP7;
|
||||
protext1 &= ~PEXT_FLOATCOORDS; //always enabled, try not to break things
|
||||
protext2 = host_client->fteprotocolextensions2 = host_client->fteprotocolextensions2 & ~(PEXT2_PREDINFO|PEXT2_REPLACEMENTDELTAS); //always disabled. kinda interferes with expectations.
|
||||
protoname = "DPP7";
|
||||
break;
|
||||
default:
|
||||
host_client->drop = true;
|
||||
protoname = "?""?""?";
|
||||
protoname = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -654,9 +657,17 @@ void SVNQ_New_f (void)
|
|||
//note that those clients will also glitch out from vanilla servers too.
|
||||
//vanilla prints something like: VERSION 1.08 SERVER (%i CRC)
|
||||
//which isn't all that useful. so lets customise it to advertise properly, as well as provide gamedir and map (file)name info
|
||||
Q_snprintfz (message, sizeof(message), "%c\n%s - "DISTRIBUTION" (%s%s%s%s %s) - %s", 2, gamedir,
|
||||
protoname,(protext1||(protext2&~(PEXT2_REPLACEMENTDELTAS|PEXT2_VOICECHAT)))?"+":"",(protext2&PEXT2_REPLACEMENTDELTAS)?"F":"",(protext2&PEXT2_VOICECHAT)?"V":"",
|
||||
if (protext2 & PEXT2_REPLACEMENTDELTAS)
|
||||
{
|
||||
Q_snprintfz (message, sizeof(message), "%c\n%s - "DISTRIBUTION" (FTENQ, %s) - %s", 2, gamedir,
|
||||
build, mapname);
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintfz (message, sizeof(message), "%c\n%s - "DISTRIBUTION" (%s%s%s, %s) - %s", 2, gamedir,
|
||||
protoname,(protext1||(protext2&~PEXT2_VOICECHAT))?"+":"",(protext2&PEXT2_VOICECHAT)?"Voip":"",
|
||||
build, mapname);
|
||||
}
|
||||
MSG_WriteByte (&host_client->netchan.message, svc_print);
|
||||
MSG_WriteString (&host_client->netchan.message,message);
|
||||
}
|
||||
|
@ -664,14 +675,10 @@ void SVNQ_New_f (void)
|
|||
if (host_client->protocol == SCP_DARKPLACES6 || host_client->protocol == SCP_DARKPLACES7)
|
||||
{
|
||||
size_t sz;
|
||||
extern cvar_t allow_download;
|
||||
char *f;
|
||||
|
||||
if (allow_download.value)
|
||||
{
|
||||
MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
|
||||
MSG_WriteString (&host_client->netchan.message, "cl_serverextension_download 1\n");
|
||||
}
|
||||
|
||||
f = COM_LoadTempFile("csprogs.dat", &sz);
|
||||
if (f)
|
||||
|
@ -687,6 +694,12 @@ void SVNQ_New_f (void)
|
|||
MSG_WriteString (&host_client->netchan.message, "cmd enablecsqc\n");
|
||||
}
|
||||
}
|
||||
else if (allow_download.value && (protext1||protext2))
|
||||
{ //technically this is a DP extension, but is separate from actual protocols and shouldn't harm anything.
|
||||
//it is annoying to have prints about unknown commands however, hence the above pext checks (which are unfortunate).
|
||||
MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
|
||||
MSG_WriteString (&host_client->netchan.message, "cl_serverextension_download 1\n");
|
||||
}
|
||||
|
||||
MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
|
||||
if (protext1)
|
||||
|
@ -1873,6 +1886,32 @@ void SV_Begin_Core(client_t *split)
|
|||
}
|
||||
else
|
||||
{
|
||||
#ifndef NOLEGACY
|
||||
sv_player->xv->clientcolors = host_client->playercolor;
|
||||
if (progstype != PROG_QW)
|
||||
{ //some redundant things, purely for dp compat
|
||||
eval_t *eval;
|
||||
edict_t *ent = split->edict;
|
||||
sv_player->v->team = host_client->playercolor&15;
|
||||
|
||||
eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "playermodel", ev_string, NULL);
|
||||
if (eval)
|
||||
svprogfuncs->SetStringField(svprogfuncs, ent, &eval->string, Info_ValueForKey(split->userinfo, "model"), false);
|
||||
|
||||
eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "playerskin", ev_string, NULL);
|
||||
if (eval)
|
||||
svprogfuncs->SetStringField(svprogfuncs, ent, &eval->string, Info_ValueForKey(split->userinfo, "skin"), false);
|
||||
|
||||
eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "netaddress", ev_string, NULL);
|
||||
if (eval)
|
||||
{
|
||||
char buf[256];
|
||||
svprogfuncs->SetStringField(svprogfuncs, ent, &eval->string, NET_AdrToString(buf, sizeof(buf), &split->netchan.remote_address), false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (split->spectator)
|
||||
{
|
||||
SV_SpawnSpectator ();
|
||||
|
@ -1986,6 +2025,14 @@ void SV_Begin_Core(client_t *split)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
split->dp_ping = NULL;
|
||||
split->dp_pl = NULL;
|
||||
if (progstype == PROG_NQ)
|
||||
{
|
||||
split->dp_ping = (float*)sv.world.progs->GetEdictFieldValue(sv.world.progs, sv_player, "ping", ev_float, NULL);
|
||||
split->dp_pl = (float*)sv.world.progs->GetEdictFieldValue(sv.world.progs, sv_player, "ping_packetloss", ev_float, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4184,11 +4231,6 @@ void SV_SetInfo_f (void)
|
|||
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
|
||||
// host_client->sendinfo = true;
|
||||
|
||||
if (progstype != PROG_QW && !strcmp(key, "bottomcolor"))
|
||||
{ //team fortress has a nasty habit of booting people without this
|
||||
sv_player->v->team = atoi(Cmd_Argv(2))+1;
|
||||
}
|
||||
|
||||
if (!strcmp(Info_ValueForKey(host_client->userinfo, key), oldval))
|
||||
return; // key hasn't changed
|
||||
|
||||
|
@ -4201,6 +4243,25 @@ void SV_SetInfo_f (void)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (progstype != PROG_QW && !strcmp(key, "bottomcolor"))
|
||||
{ //team fortress has a nasty habit of booting people without this
|
||||
sv_player->v->team = atoi(Cmd_Argv(2))+1;
|
||||
}
|
||||
#ifndef NOLEGACY
|
||||
if (progstype != PROG_QW && !strcmp(key, "model"))
|
||||
{
|
||||
eval_t *eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, sv_player, "playermodel", ev_string, NULL);
|
||||
if (eval)
|
||||
svprogfuncs->SetStringField(svprogfuncs, sv_player, &eval->string, Cmd_Argv(2), false);
|
||||
}
|
||||
if (progstype != PROG_QW && !strcmp(key, "skin"))
|
||||
{
|
||||
eval_t *eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, sv_player, "playerskin", ev_string, NULL);
|
||||
if (eval)
|
||||
svprogfuncs->SetStringField(svprogfuncs, sv_player, &eval->string, Cmd_Argv(2), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// process any changed values
|
||||
SV_ExtractFromUserinfo (host_client, true);
|
||||
|
||||
|
@ -4801,6 +4862,14 @@ void SV_SetUpClientEdict (client_t *cl, edict_t *ent)
|
|||
bc = 0;
|
||||
ent->xv->clientcolors = 16*tc + bc;
|
||||
}
|
||||
|
||||
cl->dp_ping = NULL;
|
||||
cl->dp_pl = NULL;
|
||||
if (progstype == PROG_NQ)
|
||||
{
|
||||
cl->dp_ping = (float*)sv.world.progs->GetEdictFieldValue(sv.world.progs, ent, "ping", ev_float, NULL);
|
||||
cl->dp_pl = (float*)sv.world.progs->GetEdictFieldValue(sv.world.progs, ent, "ping_packetloss", ev_float, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -5541,6 +5610,17 @@ static void SVNQ_NQColour_f (void)
|
|||
SV_ExtractFromUserinfo (host_client, true);
|
||||
}
|
||||
|
||||
static void SVNQ_DPModel_f (void)
|
||||
{
|
||||
Cmd_TokenizeString(va("setinfo model \"%s\"\n", Cmd_Argv(1)), false, false);
|
||||
SV_SetInfo_f();
|
||||
}
|
||||
static void SVNQ_DPSkin_f (void)
|
||||
{
|
||||
Cmd_TokenizeString(va("setinfo skin \"%s\"\n", Cmd_Argv(1)), false, false);
|
||||
SV_SetInfo_f();
|
||||
}
|
||||
|
||||
static void SVNQ_Ping_f(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -5597,9 +5677,16 @@ static void SVNQ_Status_f(void)
|
|||
SV_PrintToClient(host_client, PRINT_HIGH, va("players: %i active (%i max)\n\n", count, min(maxclients.ival+maxspectators.ival,sv.allocated_client_slots)));//must be last
|
||||
for (i=0,cl=svs.clients ; i<sv.allocated_client_slots ; i++,cl++)
|
||||
{
|
||||
int hours, mins, secs;
|
||||
if (!cl->state)
|
||||
continue;
|
||||
SV_PrintToClient(host_client, PRINT_HIGH, va("#%i\n", i+1));
|
||||
secs = realtime - cl->connection_started;
|
||||
mins = secs/60;
|
||||
secs -= mins*60;
|
||||
hours = mins/60;
|
||||
mins -= hours*60;
|
||||
|
||||
SV_PrintToClient(host_client, PRINT_HIGH, va("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, cl->name, cl->old_frags, hours, mins, secs));
|
||||
SV_PrintToClient(host_client, PRINT_HIGH, va(" %s\n", SV_PlayerPublicAddress(cl)));
|
||||
}
|
||||
}
|
||||
|
@ -5887,8 +5974,8 @@ ucmd_t nqucmds[] =
|
|||
{"setinfo", SV_SetInfo_f},
|
||||
{"name", SVNQ_NQInfo_f},
|
||||
{"color", SVNQ_NQColour_f},
|
||||
{"playermodel", NULL},
|
||||
{"playerskin", NULL},
|
||||
{"playermodel", SVNQ_DPModel_f},
|
||||
{"playerskin", SVNQ_DPSkin_f},
|
||||
{"rate", SV_Rate_f},
|
||||
{"rate_burstsize", NULL},
|
||||
|
||||
|
@ -6146,7 +6233,7 @@ float V_CalcRoll (vec3_t angles, vec3_t velocity)
|
|||
|
||||
vec3_t pmove_mins, pmove_maxs;
|
||||
|
||||
static qboolean AddEntityToPmove(edict_t *player, edict_t *check)
|
||||
static qboolean AddEntityToPmove(world_t *w, wedict_t *player, wedict_t *check)
|
||||
{
|
||||
physent_t *pe;
|
||||
int solid = check->v->solid;
|
||||
|
@ -6163,7 +6250,7 @@ static qboolean AddEntityToPmove(edict_t *player, edict_t *check)
|
|||
pmove.numphysent++;
|
||||
|
||||
VectorCopy (check->v->origin, pe->origin);
|
||||
pe->info = NUM_FOR_EDICT(svprogfuncs, check);
|
||||
pe->info = NUM_FOR_EDICT(w->progs, check);
|
||||
pe->nonsolid = solid == SOLID_TRIGGER;
|
||||
pe->isportal = solid == SOLID_PORTAL;
|
||||
q1contents = (int)check->v->skin;
|
||||
|
@ -6215,28 +6302,30 @@ static qboolean AddEntityToPmove(edict_t *player, edict_t *check)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
====================
|
||||
AddLinksToPmove
|
||||
|
||||
====================
|
||||
*/
|
||||
void AddLinksToPmove ( edict_t *player, areanode_t *node )
|
||||
#if 1
|
||||
#ifdef USEAREAGRID
|
||||
extern size_t areagridsequence;
|
||||
static void AddLinksToPmove (world_t *w, wedict_t *player, areagridlink_t *node)
|
||||
{
|
||||
int Q1_HullPointContents (hull_t *hull, int num, vec3_t p);
|
||||
link_t *l, *next;
|
||||
edict_t *check;
|
||||
wedict_t *check;
|
||||
int pl;
|
||||
int i;
|
||||
int solid;
|
||||
|
||||
pl = EDICT_TO_PROG(svprogfuncs, player);
|
||||
pl = EDICT_TO_PROG(w->progs, player);
|
||||
|
||||
// touch linked edicts
|
||||
for (l = node->edicts.next ; l != &node->edicts ; l = next)
|
||||
for (l = node->l.next ; l != &node->l ; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
check = (edict_t*)EDICT_FROM_AREA(l);
|
||||
check = ((areagridlink_t*)l)->ed;
|
||||
|
||||
if (check->gridareasequence == areagridsequence)
|
||||
continue;
|
||||
check->gridareasequence = areagridsequence;
|
||||
|
||||
if (check->v->owner == pl)
|
||||
continue; // player's own missile
|
||||
|
@ -6261,38 +6350,33 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
|
|||
if (i != 3)
|
||||
continue;
|
||||
|
||||
if (!AddEntityToPmove(player, check))
|
||||
if (!AddEntityToPmove(w, player, check))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// recurse down both sides
|
||||
if (node->axis == -1)
|
||||
return;
|
||||
|
||||
if (pmove_maxs[node->axis] > node->dist)
|
||||
AddLinksToPmove (player, node->children[0]);
|
||||
if (pmove_mins[node->axis] < node->dist)
|
||||
AddLinksToPmove (player, node->children[1]);
|
||||
}
|
||||
|
||||
//ignores mins/maxs.
|
||||
//portals are expected to be weird. player movement code is nasty.
|
||||
void AddLinksToPmove_Force ( edict_t *player, areanode_t *node )
|
||||
static void AddPortalsToPmove (world_t *w, wedict_t *player, areagridlink_t *node)
|
||||
{
|
||||
link_t *l, *next;
|
||||
edict_t *check;
|
||||
wedict_t *check;
|
||||
int pl;
|
||||
// int i;
|
||||
int solid;
|
||||
|
||||
pl = EDICT_TO_PROG(svprogfuncs, player);
|
||||
pl = EDICT_TO_PROG(w->progs, player);
|
||||
|
||||
// touch linked edicts
|
||||
for (l = node->edicts.next ; l != &node->edicts ; l = next)
|
||||
for (l = node->l.next ; l != &node->l ; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
check = (edict_t*)EDICT_FROM_AREA(l);
|
||||
check = ((areagridlink_t*)l)->ed;
|
||||
|
||||
if (check->gridareasequence == areagridsequence)
|
||||
continue;
|
||||
check->gridareasequence = areagridsequence;
|
||||
|
||||
if (check->v->owner == pl)
|
||||
continue; // player's own missile
|
||||
|
@ -6309,7 +6393,73 @@ void AddLinksToPmove_Force ( edict_t *player, areanode_t *node )
|
|||
//|| (solid == SOLID_PHASEH2 && progstype == PROG_H2) //logically matches hexen2, but I hate it
|
||||
)
|
||||
{
|
||||
if (!AddEntityToPmove(player, check))
|
||||
if (!AddEntityToPmove(w, player, check))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void AddAllLinksToPmove (world_t *w, wedict_t *player)
|
||||
{
|
||||
int ming[2], maxg[2], g[2];
|
||||
CALCAREAGRIDBOUNDS(w, pmove_mins, pmove_maxs);
|
||||
|
||||
areagridsequence++;
|
||||
|
||||
AddLinksToPmove(w, player, &w->jumboarea);
|
||||
for (g[0] = ming[0]; g[0] < maxg[0]; g[0]++)
|
||||
for (g[1] = ming[1]; g[1] < maxg[1]; g[1]++)
|
||||
AddLinksToPmove(w, player, &w->gridareas[g[0] + g[1]*w->gridsize[0]]);
|
||||
|
||||
AddPortalsToPmove(w, player, &w->portallist);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
====================
|
||||
AddLinksToPmove
|
||||
|
||||
====================
|
||||
*/
|
||||
void AddLinksToPmove (world_t *w, wedict_t *player, areanode_t *node)
|
||||
{
|
||||
int Q1_HullPointContents (hull_t *hull, int num, vec3_t p);
|
||||
link_t *l, *next;
|
||||
wedict_t *check;
|
||||
int pl;
|
||||
int i;
|
||||
int solid;
|
||||
|
||||
pl = EDICT_TO_PROG(w->progs, player);
|
||||
|
||||
// touch linked edicts
|
||||
for (l = node->edicts.next ; l != &node->edicts ; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
check = (wedict_t*)EDICT_FROM_AREA(l);
|
||||
|
||||
if (check->v->owner == pl)
|
||||
continue; // player's own missile
|
||||
if (check == player)
|
||||
continue;
|
||||
solid = check->v->solid;
|
||||
if (
|
||||
(solid == SOLID_TRIGGER && check->v->skin < 0)
|
||||
|| solid == SOLID_BSP
|
||||
|| solid == SOLID_PORTAL
|
||||
|| solid == SOLID_BBOX
|
||||
|| solid == SOLID_SLIDEBOX
|
||||
|| solid == SOLID_LADDER
|
||||
//|| (solid == SOLID_PHASEH2 && progstype == PROG_H2) //logically matches hexen2, but I hate it
|
||||
)
|
||||
{
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (check->v->absmin[i] > pmove_maxs[i]
|
||||
|| check->v->absmax[i] < pmove_mins[i])
|
||||
break;
|
||||
if (i != 3)
|
||||
continue;
|
||||
|
||||
if (!AddEntityToPmove(w, player, check))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -6319,12 +6469,61 @@ void AddLinksToPmove_Force ( edict_t *player, areanode_t *node )
|
|||
return;
|
||||
|
||||
if (pmove_maxs[node->axis] > node->dist)
|
||||
AddLinksToPmove_Force (player, node->children[0]);
|
||||
AddLinksToPmove (w, player, node->children[0]);
|
||||
if (pmove_mins[node->axis] < node->dist)
|
||||
AddLinksToPmove_Force (player, node->children[1]);
|
||||
AddLinksToPmove (w, player, node->children[1]);
|
||||
}
|
||||
|
||||
//ignores mins/maxs.
|
||||
//portals are expected to be weird. player movement code is nasty.
|
||||
void AddLinksToPmove_Force (world_t *w, wedict_t *player, areanode_t *node)
|
||||
{
|
||||
link_t *l, *next;
|
||||
wedict_t *check;
|
||||
int pl;
|
||||
// int i;
|
||||
int solid;
|
||||
|
||||
pl = EDICT_TO_PROG(w->progs, player);
|
||||
|
||||
// touch linked edicts
|
||||
for (l = node->edicts.next ; l != &node->edicts ; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
check = (wedict_t*)EDICT_FROM_AREA(l);
|
||||
|
||||
if (check->v->owner == pl)
|
||||
continue; // player's own missile
|
||||
if (check == player)
|
||||
continue;
|
||||
solid = check->v->solid;
|
||||
if (
|
||||
(solid == SOLID_TRIGGER && check->v->skin < 0)
|
||||
|| solid == SOLID_BSP
|
||||
|| solid == SOLID_PORTAL
|
||||
|| solid == SOLID_BBOX
|
||||
|| solid == SOLID_SLIDEBOX
|
||||
|| solid == SOLID_LADDER
|
||||
//|| (solid == SOLID_PHASEH2 && progstype == PROG_H2) //logically matches hexen2, but I hate it
|
||||
)
|
||||
{
|
||||
if (!AddEntityToPmove(w, player, check))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// recurse down both sides
|
||||
if (node->axis == -1)
|
||||
return;
|
||||
|
||||
if (pmove_maxs[node->axis] > node->dist)
|
||||
AddLinksToPmove_Force (w, player, node->children[0]);
|
||||
if (pmove_mins[node->axis] < node->dist)
|
||||
AddLinksToPmove_Force (w, player, node->children[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
/*
|
||||
================
|
||||
AddAllEntsToPmove
|
||||
|
@ -6332,17 +6531,17 @@ AddAllEntsToPmove
|
|||
For debugging
|
||||
================
|
||||
*/
|
||||
void AddAllEntsToPmove (edict_t *player)
|
||||
void AddAllEntsToPmove (wedict_t *player, world_t *w)
|
||||
{
|
||||
int e;
|
||||
edict_t *check;
|
||||
wedict_t *check;
|
||||
int i;
|
||||
int pl;
|
||||
|
||||
pl = EDICT_TO_PROG(svprogfuncs, player);
|
||||
for (e=1 ; e<sv.world.num_edicts ; e++)
|
||||
pl = EDICT_TO_PROG(w->progs, player);
|
||||
for (e=1 ; e<w->num_edicts ; e++)
|
||||
{
|
||||
check = EDICT_NUM(svprogfuncs, e);
|
||||
check = EDICT_NUM(w->progs, e);
|
||||
if (ED_ISFREE(check))
|
||||
continue;
|
||||
if (check->v->owner == pl)
|
||||
|
@ -6366,6 +6565,7 @@ void AddAllEntsToPmove (edict_t *player)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int SV_PMTypeForClient (client_t *cl, edict_t *ent)
|
||||
{
|
||||
|
@ -6482,8 +6682,15 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
|
|||
#ifdef NEWSPEEDCHEATPROT
|
||||
if (ucmd->msec && host_client->msecs > 500)
|
||||
host_client->msecs = 500;
|
||||
if (ucmd->msec > host_client->msecs)
|
||||
{ //they're over their timeslice allocation
|
||||
//if they're not taking the piss then be prepared to truncate the frame. this should hide clockskew without allowing full-on speedcheats.
|
||||
if (ucmd->msec > 10)
|
||||
ucmd->msec -= 1;
|
||||
if (ucmd->msec > host_client->msecs)
|
||||
return;
|
||||
ucmd->msec = host_client->msecs;
|
||||
}
|
||||
host_client->msecs -= ucmd->msec;
|
||||
#else
|
||||
// DMW copied this KK hack copied from QuakeForge anti-cheat
|
||||
|
@ -6852,12 +7059,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
|
|||
pmove_maxs[i] = pmove.origin[i] + 256;
|
||||
}
|
||||
sv_player->xv->pmove_flags = (int)sv_player->xv->pmove_flags & ~PMF_LADDER; //assume not touching ladder trigger
|
||||
#if 1
|
||||
AddLinksToPmove ( sv_player, sv.world.areanodes );
|
||||
#else
|
||||
AddAllEntsToPmove (sv_player);
|
||||
#endif
|
||||
AddLinksToPmove_Force ( sv_player, &sv.world.portallist );
|
||||
AddAllLinksToPmove (&sv.world, (wedict_t*)sv_player);
|
||||
|
||||
if ((int)sv_player->xv->pmove_flags & PMF_LADDER)
|
||||
pmove.onladder = true;
|
||||
|
@ -7949,6 +8151,7 @@ void SVNQ_ReadClientMove (usercmd_t *move)
|
|||
}
|
||||
else
|
||||
{
|
||||
host_client->last_sequence = 0; //let the client know that prediction is fucked, by not acking any input frames.
|
||||
if (i)
|
||||
host_client->edict->v->impulse = i;
|
||||
host_client->isindependant = false;
|
||||
|
@ -7959,14 +8162,14 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
|
|||
{
|
||||
int c;
|
||||
char *s;
|
||||
client_frame_t *frame;
|
||||
// client_frame_t *frame;
|
||||
|
||||
cl->netchan.outgoing_sequence++;
|
||||
cl->netchan.incoming_acknowledged = cl->netchan.outgoing_sequence-1;
|
||||
|
||||
// calc ping time
|
||||
frame = &cl->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
|
||||
frame->ping_time = -1;
|
||||
// frame = &cl->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
|
||||
// frame->ping_time = -1;
|
||||
|
||||
// make sure the reply sequence number matches the incoming
|
||||
// sequence number
|
||||
|
@ -7976,11 +8179,11 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
|
|||
// cl->send_message = false; // don't reply, sequences have slipped
|
||||
|
||||
// save time for ping calculations
|
||||
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
|
||||
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;
|
||||
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].move_msecs = -1;
|
||||
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].packetsizein = net_message.cursize;
|
||||
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].packetsizeout = 0;
|
||||
// cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
|
||||
// cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;
|
||||
// cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].move_msecs = -1;
|
||||
// cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].packetsizein = net_message.cursize;
|
||||
// cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].packetsizeout = 0;
|
||||
|
||||
host_client = cl;
|
||||
sv_player = host_client->edict;
|
||||
|
@ -8047,6 +8250,7 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
|
|||
if (cl->delta_sequence == -1 && cl->pendingdeltabits)
|
||||
cl->pendingdeltabits[0] = UF_REMOVE;
|
||||
SV_AckEntityFrame(cl, cl->delta_sequence);
|
||||
cl->frameunion.frames[cl->delta_sequence&UPDATE_MASK].ping_time = realtime - cl->frameunion.frames[cl->delta_sequence&UPDATE_MASK].senttime;
|
||||
break;
|
||||
case clcdp_ackdownloaddata:
|
||||
SV_DarkPlacesDownloadAck(cl);
|
||||
|
|
|
@ -791,6 +791,7 @@ static model_t *QDECL SVQ2_GetCModel(world_t *w, int modelindex)
|
|||
|
||||
void SVQ2_InitWorld(void)
|
||||
{
|
||||
World_ClearWorld_Nodes (&sv.world, false);
|
||||
sv.world.Get_CModel = SVQ2_GetCModel;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
#ifdef Q3SERVER
|
||||
|
||||
#ifndef MAX_ENT_CLUSTERS
|
||||
#define MAX_ENT_CLUSTERS 16
|
||||
#endif
|
||||
|
||||
#define USEBOTLIB
|
||||
|
||||
|
@ -119,9 +122,14 @@ const char *mapentspointer;
|
|||
|
||||
|
||||
|
||||
|
||||
//these entities are private to the engine. gamecode shall not see this.
|
||||
typedef struct {
|
||||
#ifdef USEAREAGRID
|
||||
areagridlink_t areas[16];
|
||||
size_t areagridsequence;
|
||||
#else
|
||||
link_t area;
|
||||
#endif
|
||||
qboolean linked;
|
||||
int areanum;
|
||||
int areanum2;
|
||||
|
@ -144,11 +152,23 @@ static void Q3G_UnlinkEntity(q3sharedEntity_t *ent)
|
|||
return; // not linked in anywhere
|
||||
}
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
{int i;
|
||||
for (i = 0; i < countof(sent->areas); i++)
|
||||
{
|
||||
if (!sent->areas[i].ed)
|
||||
break;
|
||||
RemoveLink(&sent->areas[i].l);
|
||||
sent->areas[i].ed = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (sent->area.prev == NULL || sent->area.next == NULL)
|
||||
SV_Error("Null entity links in linked entity\n");
|
||||
|
||||
RemoveLink(&sent->area);
|
||||
sent->area.prev = sent->area.next = NULL;
|
||||
#endif
|
||||
|
||||
sent->linked = false;
|
||||
}
|
||||
|
@ -181,7 +201,11 @@ static model_t *Q3G_GetCModel(unsigned int modelindex)
|
|||
|
||||
static void Q3G_LinkEntity(q3sharedEntity_t *ent)
|
||||
{
|
||||
#ifdef USEAREAGRID
|
||||
int ming[2], maxg[2], g[2], ga;
|
||||
#else
|
||||
areanode_t *node;
|
||||
#endif
|
||||
q3serverEntity_t *sent;
|
||||
int leafs[MAX_TOTAL_ENT_LEAFS];
|
||||
int clusters[MAX_TOTAL_ENT_LEAFS];
|
||||
|
@ -346,6 +370,23 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent)
|
|||
sent->linked = true;
|
||||
|
||||
// find the first node that the ent's box crosses
|
||||
#ifdef USEAREAGRID
|
||||
CALCAREAGRIDBOUNDS(&sv.world, ent->r.absmin, ent->r.absmax);
|
||||
if ((maxg[0]-ming[0])*(maxg[1]-ming[1]) > countof(sent->areas))
|
||||
{ //entity is too large to fit in our grid. shove it in the overflow
|
||||
sent->areas[0].ed = sent;
|
||||
InsertLinkBefore (&sent->areas[0].l, &sv.world.jumboarea.l);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ga = 0, g[0] = ming[0]; g[0] < maxg[0]; g[0]++)
|
||||
for ( g[1] = ming[1]; g[1] < maxg[1]; g[1]++, ga++)
|
||||
{
|
||||
sent->areas[ga].ed = sent;
|
||||
InsertLinkBefore (&sent->areas[ga].l, &sv.world.gridareas[g[0] + g[1]*sv.world.gridsize[0]].l);
|
||||
}
|
||||
}
|
||||
#else
|
||||
node = sv.world.areanodes;
|
||||
while(1)
|
||||
{
|
||||
|
@ -361,8 +402,53 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent)
|
|||
}
|
||||
// link it in
|
||||
InsertLinkBefore((link_t *)&sent->area, &node->edicts);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
static int SVQ3_EntitiesInBoxNode(areagridlink_t *node, vec3_t mins, vec3_t maxs, int *list, int maxcount)
|
||||
{
|
||||
link_t *l, *next;
|
||||
q3serverEntity_t *sent;
|
||||
q3sharedEntity_t *gent;
|
||||
|
||||
int linkcount = 0;
|
||||
|
||||
//work out who they are first.
|
||||
for (l = node->l.next ; l != &node->l ; l = next)
|
||||
{
|
||||
if (maxcount == linkcount)
|
||||
return linkcount;
|
||||
|
||||
next = l->next;
|
||||
sent = ((areagridlink_t*)l)->ed;
|
||||
if (sent->areagridsequence != areagridsequence)
|
||||
{
|
||||
sent->areagridsequence = areagridsequence;
|
||||
gent = GENTITY_FOR_SENTITY(sent);
|
||||
|
||||
if (!BoundsIntersect(mins, maxs, gent->r.absmin, gent->r.absmax))
|
||||
continue;
|
||||
|
||||
list[linkcount++] = NUM_FOR_GENTITY(gent);
|
||||
}
|
||||
}
|
||||
|
||||
return linkcount;
|
||||
}
|
||||
static int SVQ3_EntitiesInBox(vec3_t mins, vec3_t maxs, int *list, int maxcount)
|
||||
{
|
||||
int ming[2], maxg[2], g[2], ga;
|
||||
int linkcount = 0;
|
||||
areagridsequence++;
|
||||
linkcount += SVQ3_EntitiesInBoxNode(&sv.world.jumboarea, mins, maxs, list+linkcount, maxcount-linkcount);
|
||||
CALCAREAGRIDBOUNDS(&sv.world, mins, maxs);
|
||||
for (ga = 0, g[0] = ming[0]; g[0] < maxg[0]; g[0]++)
|
||||
for ( g[1] = ming[1]; g[1] < maxg[1]; g[1]++, ga++)
|
||||
linkcount += SVQ3_EntitiesInBoxNode(&sv.world.gridareas[g[0] + g[1]*sv.world.gridsize[0]], mins, maxs, list+linkcount, maxcount-linkcount);
|
||||
return linkcount;
|
||||
}
|
||||
#else
|
||||
static int SVQ3_EntitiesInBoxNode(areanode_t *node, vec3_t mins, vec3_t maxs, int *list, int maxcount)
|
||||
{
|
||||
link_t *l, *next;
|
||||
|
@ -405,6 +491,7 @@ static int SVQ3_EntitiesInBox(vec3_t mins, vec3_t maxs, int *list, int maxcount)
|
|||
return 0;
|
||||
return SVQ3_EntitiesInBoxNode(sv.world.areanodes, mins, maxs, list, maxcount);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ENTITYNUM_NONE (MAX_GENTITIES-1)
|
||||
#define ENTITYNUM_WORLD (MAX_GENTITIES-2)
|
||||
|
|
|
@ -31,6 +31,8 @@ line of sight checks trace->crosscontent, but bullets don't
|
|||
|
||||
*/
|
||||
|
||||
size_t areagridsequence; //used to avoid poking the same ent twice.
|
||||
|
||||
extern cvar_t sv_compatiblehulls;
|
||||
extern cvar_t sv_gameplayfix_nolinknonsolid;
|
||||
|
||||
|
@ -209,6 +211,7 @@ ENTITY AREA CHECKING
|
|||
===============================================================================
|
||||
*/
|
||||
|
||||
#if defined(Q2SERVER) || !defined(USEAREAGRID)
|
||||
/*
|
||||
===============
|
||||
SV_CreateAreaNode
|
||||
|
@ -260,10 +263,12 @@ SV_ClearWorld
|
|||
|
||||
===============
|
||||
*/
|
||||
void World_ClearWorld (world_t *w, qboolean relink)
|
||||
void World_ClearWorld_Nodes (world_t *w, qboolean relink)
|
||||
{
|
||||
#if !defined(USEAREAGRID)
|
||||
int i;
|
||||
wedict_t *ent;
|
||||
#endif
|
||||
int maxdepth;
|
||||
vec3_t mins, maxs;
|
||||
if (w->worldmodel)
|
||||
|
@ -279,9 +284,11 @@ void World_ClearWorld (world_t *w, qboolean relink)
|
|||
|
||||
World_InitBoxHull ();
|
||||
|
||||
#if !defined(USEAREAGRID)
|
||||
memset (&w->portallist, 0, sizeof(w->portallist));
|
||||
ClearLink (&w->portallist.edicts);
|
||||
w->portallist.axis = -1;
|
||||
#endif
|
||||
|
||||
maxdepth = 8;
|
||||
|
||||
|
@ -296,7 +303,7 @@ void World_ClearWorld (world_t *w, qboolean relink)
|
|||
w->numareanodes = 0;
|
||||
World_CreateAreaNode (w, 0, mins, maxs);
|
||||
|
||||
|
||||
#if !defined(USEAREAGRID)
|
||||
if (relink)
|
||||
{
|
||||
for (i=0 ; i<w->num_edicts ; i++)
|
||||
|
@ -310,8 +317,92 @@ void World_ClearWorld (world_t *w, qboolean relink)
|
|||
World_LinkEdict (w, ent, false); // relink ents so touch functions continue to work.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
static void World_ClearWorld_AreaGrid (world_t *w, qboolean relink)
|
||||
{
|
||||
int numareas = 1;
|
||||
int i, j;
|
||||
wedict_t *ent;
|
||||
vec3_t mins, maxs, size;
|
||||
if (w->worldmodel)
|
||||
{
|
||||
VectorCopy(w->worldmodel->mins, mins);
|
||||
VectorCopy(w->worldmodel->maxs, maxs);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet(mins, -4096, -4096, -4096);
|
||||
VectorSet(maxs, 4096, 4096, 4096);
|
||||
}
|
||||
Vector2Set(w->gridsize, 128, 128);
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
size[i] = maxs[i] - mins[i];
|
||||
size[i] /= w->gridsize[i];
|
||||
//enforce a minimum grid size, so things don't end up getting added to every single node
|
||||
if (size[i] < 128)
|
||||
size[i] = 128;
|
||||
w->gridscale[i] = size[i];
|
||||
w->gridbias[i] = -mins[i];
|
||||
|
||||
numareas *= w->gridsize[i];
|
||||
}
|
||||
|
||||
World_InitBoxHull ();
|
||||
|
||||
if (w->gridareas)
|
||||
memset (w->gridareas, 0, sizeof(*w->gridareas)*numareas);
|
||||
else
|
||||
w->gridareas = Z_Malloc(sizeof(*w->gridareas)*numareas);
|
||||
|
||||
for (i = 0; i < numareas; i++)
|
||||
ClearLink (&w->gridareas[i].l);
|
||||
ClearLink (&w->jumboarea.l);
|
||||
ClearLink (&w->portallist.l);
|
||||
|
||||
|
||||
if (relink)
|
||||
{
|
||||
for (i=0 ; i<w->num_edicts ; i++)
|
||||
{
|
||||
ent = WEDICT_NUM(w->progs, i);
|
||||
if (!ent)
|
||||
continue;
|
||||
for (j = 0; j < countof(ent->gridareas); j++)
|
||||
{
|
||||
if (!ent->gridareas[j].l.prev)
|
||||
break; // not linked in anywhere
|
||||
ClearLink(&ent->gridareas[j].l);
|
||||
}
|
||||
if (ED_ISFREE(ent))
|
||||
continue;
|
||||
World_LinkEdict (w, ent, false); // relink ents so touch functions continue to work.
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void World_ClearWorld (world_t *w, qboolean relink)
|
||||
{
|
||||
#ifdef Q2SERVER
|
||||
if (w == &sv.world && svs.gametype == GT_QUAKE2)
|
||||
World_ClearWorld_Nodes(w, relink);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef USEAREAGRID
|
||||
World_ClearWorld_AreaGrid(w, relink);
|
||||
#else
|
||||
World_ClearWorld_Nodes(w, relink);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if !defined(USEAREAGRID)
|
||||
|
||||
/*
|
||||
===============
|
||||
|
@ -327,16 +418,14 @@ void World_UnlinkEdict (wedict_t *ent)
|
|||
ent->area.prev = ent->area.next = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
SV_TouchLinks
|
||||
====================
|
||||
*/
|
||||
#define MAX_NODELINKS 256 //all this means is that any more than this will not touch.
|
||||
static wedict_t *nodelinks[MAX_NODELINKS];
|
||||
void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node)
|
||||
{
|
||||
static wedict_t *nodelinks[256]; //all this means is that any more than this will not touch. probably you won't have that many valid triggers
|
||||
link_t *l, *next;
|
||||
wedict_t *touch;
|
||||
|
||||
|
@ -345,7 +434,7 @@ void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node)
|
|||
//work out who they are first.
|
||||
for (l = node->edicts.next ; l != &node->edicts ; l = next)
|
||||
{
|
||||
if (linkcount == MAX_NODELINKS)
|
||||
if (linkcount == countof(nodelinks))
|
||||
break;
|
||||
next = l->next;
|
||||
touch = EDICT_FROM_AREA(l);
|
||||
|
@ -406,75 +495,6 @@ void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node)
|
|||
if (ent->v->absmin[node->axis] < node->dist)
|
||||
World_TouchLinks (w, ent, node->children[1]);
|
||||
}
|
||||
|
||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
||||
void Q23BSP_FindTouchedLeafs(model_t *model, struct pvscache_s *ent, float *mins, float *maxs)
|
||||
{
|
||||
#define MAX_TOTAL_ENT_LEAFS 128
|
||||
int leafs[MAX_TOTAL_ENT_LEAFS];
|
||||
int clusters[MAX_TOTAL_ENT_LEAFS];
|
||||
int num_leafs;
|
||||
int topnode;
|
||||
int i, j;
|
||||
int area;
|
||||
int nullarea = (model->fromgame == fg_quake2)?0:-1;
|
||||
|
||||
//ent->num_leafs == q2's ent->num_clusters
|
||||
ent->num_leafs = 0;
|
||||
ent->areanum = nullarea;
|
||||
ent->areanum2 = nullarea;
|
||||
|
||||
if (!mins || !maxs)
|
||||
return;
|
||||
|
||||
//get all leafs, including solids
|
||||
num_leafs = CM_BoxLeafnums (model, mins, maxs,
|
||||
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
|
||||
|
||||
// set areas
|
||||
for (i=0 ; i<num_leafs ; i++)
|
||||
{
|
||||
clusters[i] = CM_LeafCluster (model, leafs[i]);
|
||||
area = CM_LeafArea (model, leafs[i]);
|
||||
if (area != nullarea)
|
||||
{ // doors may legally straggle two areas,
|
||||
// but nothing should ever need more than that
|
||||
if (ent->areanum != nullarea && ent->areanum != area)
|
||||
ent->areanum2 = area;
|
||||
else
|
||||
ent->areanum = area;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
|
||||
{ // assume we missed some leafs, and mark by headnode
|
||||
ent->num_leafs = -1;
|
||||
ent->headnode = topnode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->num_leafs = 0;
|
||||
for (i=0 ; i<num_leafs ; i++)
|
||||
{
|
||||
if (clusters[i] == -1)
|
||||
continue; // not a visible leaf
|
||||
for (j=0 ; j<i ; j++)
|
||||
if (clusters[j] == clusters[i])
|
||||
break;
|
||||
if (j == i)
|
||||
{
|
||||
if (ent->num_leafs == MAX_ENT_LEAFS)
|
||||
{ // assume we missed some leafs, and mark by headnode
|
||||
ent->num_leafs = -1;
|
||||
ent->headnode = topnode;
|
||||
break;
|
||||
}
|
||||
|
||||
ent->leafnums[ent->num_leafs++] = clusters[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -485,10 +505,14 @@ SV_LinkEdict
|
|||
*/
|
||||
void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers)
|
||||
{
|
||||
#ifdef USEAREAGRID
|
||||
World_UnlinkEdict (ent); // unlink from old position
|
||||
#else
|
||||
areanode_t *node;
|
||||
|
||||
if (ent->area.prev)
|
||||
World_UnlinkEdict (ent); // unlink from old position
|
||||
#endif
|
||||
|
||||
if (ent == w->edicts)
|
||||
return; // don't add the world
|
||||
|
@ -604,6 +628,34 @@ void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers)
|
|||
if (ent->v->solid == SOLID_NOT && !sv_gameplayfix_nolinknonsolid.ival)
|
||||
return;
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
// find the first node that the ent's box crosses
|
||||
if (ent->v->solid == SOLID_PORTAL)
|
||||
{
|
||||
ent->gridareas[0].ed = ent;
|
||||
InsertLinkBefore (&ent->gridareas[0].l, &w->portallist.l);
|
||||
}
|
||||
else
|
||||
{
|
||||
int ming[2], maxg[2], g[2], ga;
|
||||
CALCAREAGRIDBOUNDS(w, ent->v->absmin, ent->v->absmax);
|
||||
|
||||
if ((maxg[0]-ming[0])*(maxg[1]-ming[1]) > countof(ent->gridareas))
|
||||
{ //entity is too large to fit in our grid. shove it in the overflow
|
||||
ent->gridareas[0].ed = ent;
|
||||
InsertLinkBefore (&ent->gridareas[0].l, &w->jumboarea.l);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ga = 0, g[0] = ming[0]; g[0] < maxg[0]; g[0]++)
|
||||
for ( g[1] = ming[1]; g[1] < maxg[1]; g[1]++, ga++)
|
||||
{
|
||||
ent->gridareas[ga].ed = ent;
|
||||
InsertLinkBefore (&ent->gridareas[ga].l, &w->gridareas[g[0] + g[1]*w->gridsize[0]].l);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
// find the first node that the ent's box crosses
|
||||
if (ent->v->solid == SOLID_PORTAL)
|
||||
node = &w->portallist;
|
||||
|
@ -626,10 +678,11 @@ void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers)
|
|||
// link it in
|
||||
|
||||
InsertLinkBefore (&ent->area, &node->edicts);
|
||||
#endif
|
||||
|
||||
// if touch_triggers, touch all entities at this node and decend for more
|
||||
if (touch_triggers && ent->v->solid != SOLID_NOT)
|
||||
World_TouchLinks (w, ent, w->areanodes);
|
||||
World_TouchAllLinks (w, ent);
|
||||
}
|
||||
|
||||
|
||||
|
@ -645,8 +698,8 @@ void VARGS WorldQ2_UnlinkEdict(world_t *w, q2edict_t *ent)
|
|||
void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
|
||||
{
|
||||
areanode_t *node;
|
||||
int leafs[MAX_TOTAL_ENT_LEAFS];
|
||||
int clusters[MAX_TOTAL_ENT_LEAFS];
|
||||
int leafs[128];
|
||||
int clusters[countof(leafs)];
|
||||
int num_leafs;
|
||||
int i, j;
|
||||
int area;
|
||||
|
@ -744,7 +797,7 @@ void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
|
|||
|
||||
//get all leafs, including solids
|
||||
num_leafs = CM_BoxLeafnums (w->worldmodel, ent->absmin, ent->absmax,
|
||||
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
|
||||
leafs, countof(leafs), &topnode);
|
||||
|
||||
// set areas
|
||||
for (i=0 ; i<num_leafs ; i++)
|
||||
|
@ -761,7 +814,7 @@ void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
|
|||
}
|
||||
}
|
||||
|
||||
if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
|
||||
if (num_leafs >= countof(leafs))
|
||||
{ // assume we missed some leafs, and mark by headnode
|
||||
ent->num_clusters = -1;
|
||||
ent->headnode = topnode;
|
||||
|
@ -993,6 +1046,79 @@ void WorldQ2_Q1BSP_LinkEdict(world_t *w, q2edict_t *ent)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
||||
void Q23BSP_FindTouchedLeafs(model_t *model, struct pvscache_s *ent, float *mins, float *maxs)
|
||||
{
|
||||
#define MAX_TOTAL_ENT_LEAFS 128
|
||||
int leafs[MAX_TOTAL_ENT_LEAFS];
|
||||
int clusters[MAX_TOTAL_ENT_LEAFS];
|
||||
int num_leafs;
|
||||
int topnode;
|
||||
int i, j;
|
||||
int area;
|
||||
int nullarea = (model->fromgame == fg_quake2)?0:-1;
|
||||
|
||||
//ent->num_leafs == q2's ent->num_clusters
|
||||
ent->num_leafs = 0;
|
||||
ent->areanum = nullarea;
|
||||
ent->areanum2 = nullarea;
|
||||
|
||||
if (!mins || !maxs)
|
||||
return;
|
||||
|
||||
//get all leafs, including solids
|
||||
num_leafs = CM_BoxLeafnums (model, mins, maxs,
|
||||
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
|
||||
|
||||
// set areas
|
||||
for (i=0 ; i<num_leafs ; i++)
|
||||
{
|
||||
clusters[i] = CM_LeafCluster (model, leafs[i]);
|
||||
area = CM_LeafArea (model, leafs[i]);
|
||||
if (area != nullarea)
|
||||
{ // doors may legally straggle two areas,
|
||||
// but nothing should ever need more than that
|
||||
if (ent->areanum != nullarea && ent->areanum != area)
|
||||
ent->areanum2 = area;
|
||||
else
|
||||
ent->areanum = area;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
|
||||
{ // assume we missed some leafs, and mark by headnode
|
||||
ent->num_leafs = -1;
|
||||
ent->headnode = topnode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->num_leafs = 0;
|
||||
for (i=0 ; i<num_leafs ; i++)
|
||||
{
|
||||
if (clusters[i] == -1)
|
||||
continue; // not a visible leaf
|
||||
for (j=0 ; j<i ; j++)
|
||||
if (clusters[j] == clusters[i])
|
||||
break;
|
||||
if (j == i)
|
||||
{
|
||||
if (ent->num_leafs == MAX_ENT_LEAFS)
|
||||
{ // assume we missed some leafs, and mark by headnode
|
||||
ent->num_leafs = -1;
|
||||
ent->headnode = topnode;
|
||||
break;
|
||||
}
|
||||
|
||||
ent->leafnums[ent->num_leafs++] = clusters[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
|
@ -1180,36 +1306,111 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
|
|||
|
||||
return trace;
|
||||
}
|
||||
#ifdef Q2SERVER
|
||||
static trace_t WorldQ2_ClipMoveToEntity (world_t *w, q2edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, unsigned int hitcontentsmask)
|
||||
{
|
||||
trace_t trace;
|
||||
model_t *model = NULL;
|
||||
|
||||
// get the clipping hull
|
||||
if (ent->s.solid == Q2SOLID_BSP)
|
||||
model = w->Get_CModel(w, ent->s.modelindex);
|
||||
#define AREA_ALL 0
|
||||
#define AREA_SOLID 1
|
||||
#define AREA_TRIGGER 2
|
||||
|
||||
if (!model || model->type != mod_brush || model->loadstate != MLS_LOADED)
|
||||
#ifdef USEAREAGRID
|
||||
|
||||
/*
|
||||
================
|
||||
SV_AreaEdicts
|
||||
================
|
||||
*/
|
||||
int World_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, wedict_t **list, int maxcount, int areatype)
|
||||
{
|
||||
vec3_t boxmins, boxmaxs;
|
||||
VectorSubtract (ent->mins, maxs, boxmins);
|
||||
VectorSubtract (ent->maxs, mins, boxmaxs);
|
||||
World_HullForBox(boxmins, boxmaxs);
|
||||
model = NULL;
|
||||
wedict_t *check;
|
||||
areagridlink_t *start, *l;
|
||||
size_t count = 0;
|
||||
int ming[2], maxg[2], g[2], ga;
|
||||
CALCAREAGRIDBOUNDS(w, mins, maxs);
|
||||
|
||||
areagridsequence++;
|
||||
|
||||
//check ents that are just too large first
|
||||
start = &w->jumboarea;
|
||||
for (l=(areagridlink_t*)start->l.next ; l != start ; l = (areagridlink_t*)l->l.next)
|
||||
{
|
||||
check = l->ed;
|
||||
|
||||
// if (check->gridareasequence == areagridsequence)
|
||||
// continue;
|
||||
check->gridareasequence = areagridsequence;
|
||||
|
||||
if (areatype != AREA_ALL)
|
||||
{
|
||||
if (check->v->solid == SOLID_NOT)
|
||||
continue; // deactivated
|
||||
|
||||
if ((check->v->solid == SOLID_TRIGGER) != (areatype == AREA_TRIGGER))
|
||||
continue;
|
||||
}
|
||||
|
||||
// trace a line through the apropriate clipping hull
|
||||
World_TransformedTrace(model, 0, 0, start, end, mins, maxs, false, &trace, ent->s.origin, ent->s.angles, hitcontentsmask);
|
||||
if (check->v->absmin[0] > maxs[0]
|
||||
|| check->v->absmin[1] > maxs[1]
|
||||
|| check->v->absmin[2] > maxs[2]
|
||||
|| check->v->absmax[0] < mins[0]
|
||||
|| check->v->absmax[1] < mins[1]
|
||||
|| check->v->absmax[2] < mins[2])
|
||||
continue; // not touching
|
||||
|
||||
// did we clip the move?
|
||||
if (trace.fraction < 1 || trace.startsolid )
|
||||
trace.ent = (edict_t *)ent;
|
||||
|
||||
return trace;
|
||||
if (count == maxcount)
|
||||
{
|
||||
Con_Printf ("World_AreaEdicts: MAXCOUNT\n");
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
#ifdef Q2BSPS
|
||||
|
||||
list[count] = check;
|
||||
count++;
|
||||
}
|
||||
|
||||
//check the actual grid now.
|
||||
for (ga = 0, g[0] = ming[0]; g[0] < maxg[0]; g[0]++)
|
||||
{
|
||||
for ( g[1] = ming[1]; g[1] < maxg[1]; g[1]++, ga++)
|
||||
{
|
||||
start = &w->gridareas[g[0] + g[1]*w->gridsize[0]];
|
||||
for (l=(areagridlink_t*)start->l.next ; l != start ; l = (areagridlink_t*)l->l.next)
|
||||
{
|
||||
check = l->ed;
|
||||
|
||||
if (check->gridareasequence == areagridsequence)
|
||||
continue;
|
||||
check->gridareasequence = areagridsequence;
|
||||
|
||||
if (areatype != AREA_ALL)
|
||||
{
|
||||
if (check->v->solid == SOLID_NOT)
|
||||
continue; // deactivated
|
||||
|
||||
if ((check->v->solid == SOLID_TRIGGER) != (areatype == AREA_TRIGGER))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (check->v->absmin[0] > maxs[0]
|
||||
|| check->v->absmin[1] > maxs[1]
|
||||
|| check->v->absmin[2] > maxs[2]
|
||||
|| check->v->absmax[0] < mins[0]
|
||||
|| check->v->absmax[1] < mins[1]
|
||||
|| check->v->absmax[2] < mins[2])
|
||||
continue; // not touching
|
||||
|
||||
if (count == maxcount)
|
||||
{
|
||||
Con_Printf ("World_AreaEdicts: MAXCOUNT\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
list[count] = check;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#else
|
||||
float *area_mins, *area_maxs;
|
||||
wedict_t **area_list;
|
||||
#ifdef Q2SERVER
|
||||
|
@ -1217,8 +1418,6 @@ q2edict_t **area_q2list;
|
|||
#endif
|
||||
int area_count, area_maxcount;
|
||||
int area_type;
|
||||
#define AREA_SOLID 1
|
||||
#define AREA_TRIGGER 2
|
||||
static void World_AreaEdicts_r (areanode_t *node)
|
||||
{
|
||||
link_t *l, *next, *start;
|
||||
|
@ -1272,8 +1471,7 @@ static void World_AreaEdicts_r (areanode_t *node)
|
|||
SV_AreaEdicts
|
||||
================
|
||||
*/
|
||||
int World_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, wedict_t **list,
|
||||
int maxcount, int areatype)
|
||||
int World_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, wedict_t **list, int maxcount, int areatype)
|
||||
{
|
||||
area_mins = mins;
|
||||
area_maxs = maxs;
|
||||
|
@ -1286,8 +1484,13 @@ int World_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, wedict_t **list,
|
|||
|
||||
return area_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q2SERVER
|
||||
float *area_mins, *area_maxs;
|
||||
q2edict_t **area_q2list;
|
||||
int area_count, area_maxcount;
|
||||
int area_type;
|
||||
static void WorldQ2_AreaEdicts_r (areanode_t *node)
|
||||
{
|
||||
link_t *l, *next, *start;
|
||||
|
@ -1460,7 +1663,6 @@ void WorldQ2_ClipMoveToEntities (world_t *w, moveclip_t *clip )
|
|||
#undef ped
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
//===========================================================================
|
||||
|
||||
//a portal is flush with a world surface behind it.
|
||||
|
@ -1647,6 +1849,192 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
|
||||
void World_TouchAllLinks (world_t *w, wedict_t *ent)
|
||||
{
|
||||
wedict_t *touchedicts[512], *touch;
|
||||
int num;
|
||||
num = World_AreaEdicts(w, ent->v->absmin, ent->v->absmax, touchedicts, countof(touchedicts), AREA_TRIGGER);
|
||||
while (num-- > 0)
|
||||
{
|
||||
touch = touchedicts[num];
|
||||
|
||||
//make sure nothing moved it away
|
||||
if (ED_ISFREE(touch))
|
||||
continue;
|
||||
if (!touch->v->touch || touch->v->solid != SOLID_TRIGGER)
|
||||
continue;
|
||||
|
||||
if (ent->v->absmin[0] > touch->v->absmax[0]
|
||||
|| ent->v->absmin[1] > touch->v->absmax[1]
|
||||
|| ent->v->absmin[2] > touch->v->absmax[2]
|
||||
|| ent->v->absmax[0] < touch->v->absmin[0]
|
||||
|| ent->v->absmax[1] < touch->v->absmin[1]
|
||||
|| ent->v->absmax[2] < touch->v->absmin[2] )
|
||||
continue;
|
||||
|
||||
if (!((int)ent->xv->dimension_solid & (int)touch->xv->dimension_hit)) //didn't change did it?...
|
||||
continue;
|
||||
|
||||
w->Event_Touch(w, touch, ent);
|
||||
|
||||
if (ED_ISFREE(ent))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void World_UnlinkEdict (wedict_t *ent)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < countof(ent->gridareas); i++)
|
||||
{
|
||||
if (!ent->gridareas[i].l.prev)
|
||||
return; // not linked in anywhere
|
||||
RemoveLink (&ent->gridareas[i].l);
|
||||
ent->gridareas[i].l.prev = ent->gridareas[i].l.next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void World_ClipToLinks (world_t *w, areagridlink_t *node, moveclip_t *clip)
|
||||
{
|
||||
link_t *l, *next;
|
||||
wedict_t *touch;
|
||||
trace_t trace;
|
||||
|
||||
// touch linked edicts
|
||||
for (l = node->l.next ; l != &node->l ; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
touch = ((areagridlink_t*)l)->ed;
|
||||
|
||||
if (touch->gridareasequence == areagridsequence)
|
||||
continue;
|
||||
touch->gridareasequence = areagridsequence;
|
||||
|
||||
if (touch->v->solid == SOLID_NOT)
|
||||
continue;
|
||||
if (touch == clip->passedict)
|
||||
continue;
|
||||
|
||||
/*if its a trigger, we only clip against it if the flags are aligned*/
|
||||
if (touch->v->solid == SOLID_TRIGGER || touch->v->solid == SOLID_LADDER)
|
||||
{
|
||||
if (!(clip->type & MOVE_TRIGGERS))
|
||||
continue;
|
||||
if (!((int)touch->v->flags & FL_FINDABLE_NONSOLID))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clip->type & MOVE_LAGGED)
|
||||
{
|
||||
//can't touch lagged ents - we do an explicit test for them later.
|
||||
if (touch->entnum-1 < w->maxlagents)
|
||||
if (w->lagents[touch->entnum-1].present)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((clip->type & MOVE_NOMONSTERS) && (touch->v->solid != SOLID_BSP && touch->v->solid != SOLID_PORTAL))
|
||||
continue;
|
||||
|
||||
if (clip->passedict)
|
||||
{
|
||||
if (w->usesolidcorpse)
|
||||
{
|
||||
#if 1
|
||||
// if (!(clip->hitcontentsmask & ((touch->v->solid == SOLID_CORPSE)?FTECONTENTS_CORPSE:FTECONTENTS_BODY)))
|
||||
// continue;
|
||||
#else
|
||||
// don't clip corpse against character
|
||||
if (clip->passedict->v->solid == SOLID_CORPSE && (touch->v->solid == SOLID_SLIDEBOX || touch->v->solid == SOLID_CORPSE))
|
||||
continue;
|
||||
// don't clip character against corpse
|
||||
if (clip->passedict->v->solid == SOLID_SLIDEBOX && touch->v->solid == SOLID_CORPSE)
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
if (!((int)clip->passedict->xv->dimension_hit & (int)touch->xv->dimension_solid))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clip->boxmins[0] > touch->v->absmax[0]
|
||||
|| clip->boxmins[1] > touch->v->absmax[1]
|
||||
|| clip->boxmins[2] > touch->v->absmax[2]
|
||||
|| clip->boxmaxs[0] < touch->v->absmin[0]
|
||||
|| clip->boxmaxs[1] < touch->v->absmin[1]
|
||||
|| clip->boxmaxs[2] < touch->v->absmin[2] )
|
||||
continue;
|
||||
|
||||
if (clip->passedict && clip->passedict->v->size[0] && !touch->v->size[0])
|
||||
continue; // points never interact
|
||||
|
||||
// might intersect, so do an exact clip
|
||||
// if (clip->trace.allsolid)
|
||||
// return;
|
||||
if (clip->passedict)
|
||||
{
|
||||
if ((wedict_t*)PROG_TO_EDICT(w->progs, touch->v->owner) == clip->passedict)
|
||||
continue; // don't clip against own missiles
|
||||
if ((wedict_t*)PROG_TO_EDICT(w->progs, clip->passedict->v->owner) == touch)
|
||||
continue; // don't clip against owner
|
||||
}
|
||||
|
||||
if (touch->v->solid == SOLID_PORTAL)
|
||||
{
|
||||
//make sure we don't hit the world if we're inside the portal
|
||||
World_PortalCSG(touch, clip->mins, clip->maxs, clip->start, clip->end, &clip->trace);
|
||||
}
|
||||
|
||||
if ((int)touch->v->flags & FL_MONSTER)
|
||||
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
|
||||
else
|
||||
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
|
||||
|
||||
if (trace.fraction < clip->trace.fraction)
|
||||
{
|
||||
//trace traveled less, but don't forget if we started in a solid.
|
||||
trace.startsolid |= clip->trace.startsolid;
|
||||
trace.allsolid |= clip->trace.allsolid;
|
||||
|
||||
if (clip->type & MOVE_ENTCHAIN)
|
||||
{
|
||||
touch->v->chain = EDICT_TO_PROG(w->progs, clip->trace.ent?clip->trace.ent:w->edicts);
|
||||
clip->trace.ent = touch;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (clip->trace.startsolid && !trace.startsolid)
|
||||
trace.ent = clip->trace.ent; //something else hit earlier, that one gets the trace entity, but not the fraction. yeah, combining traces like this was always going to be weird.
|
||||
else
|
||||
trace.ent = touch;
|
||||
clip->trace = trace;
|
||||
}
|
||||
}
|
||||
else if (trace.startsolid || trace.allsolid)
|
||||
{
|
||||
//even if the trace traveled less, we still care if it was in a solid.
|
||||
clip->trace.startsolid |= trace.startsolid;
|
||||
clip->trace.allsolid |= trace.allsolid;
|
||||
if (!clip->trace.ent)
|
||||
clip->trace.ent = touch;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void World_ClipToAllLinks (world_t *w, moveclip_t *clip)
|
||||
{
|
||||
int ming[2], maxg[2], g[2];
|
||||
areagridsequence++;
|
||||
World_ClipToLinks(w, &w->jumboarea, clip);
|
||||
|
||||
CALCAREAGRIDBOUNDS(w, clip->boxmins, clip->boxmaxs);
|
||||
|
||||
for ( g[0] = ming[0]; g[0] < maxg[0]; g[0]++)
|
||||
for (g[1] = ming[1]; g[1] < maxg[1]; g[1]++)
|
||||
{
|
||||
World_ClipToLinks(w, &w->gridareas[g[0] + g[1]*w->gridsize[0]], clip);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/*
|
||||
====================
|
||||
SV_ClipToLinks
|
||||
|
@ -1773,69 +2161,6 @@ static void World_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip)
|
|||
}
|
||||
}
|
||||
|
||||
// recurse down both sides
|
||||
if (node->axis == -1)
|
||||
return;
|
||||
|
||||
if ( clip->boxmaxs[node->axis] > node->dist )
|
||||
World_ClipToLinks (w, node->children[0], clip );
|
||||
if ( clip->boxmins[node->axis] < node->dist )
|
||||
World_ClipToLinks (w, node->children[1], clip );
|
||||
}
|
||||
#ifdef Q2SERVER
|
||||
static void WorldQ2_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip)
|
||||
{
|
||||
link_t *l, *next;
|
||||
q2edict_t *touch;
|
||||
trace_t trace;
|
||||
|
||||
// touch linked edicts
|
||||
for (l = node->edicts.next ; l != &node->edicts ; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
touch = Q2EDICT_FROM_AREA(l);
|
||||
if (touch->s.solid == Q2SOLID_NOT)
|
||||
continue;
|
||||
if (touch == clip->q2passedict)
|
||||
continue;
|
||||
if (touch->s.solid == Q2SOLID_TRIGGER)
|
||||
SV_Error ("Trigger in clipping list");
|
||||
|
||||
if (clip->type & MOVE_NOMONSTERS && touch->s.solid != Q2SOLID_BSP)
|
||||
continue;
|
||||
|
||||
if (clip->boxmins[0] > touch->absmax[0]
|
||||
|| clip->boxmins[1] > touch->absmax[1]
|
||||
|| clip->boxmins[2] > touch->absmax[2]
|
||||
|| clip->boxmaxs[0] < touch->absmin[0]
|
||||
|| clip->boxmaxs[1] < touch->absmin[1]
|
||||
|| clip->boxmaxs[2] < touch->absmin[2] )
|
||||
continue;
|
||||
|
||||
if (clip->q2passedict && clip->q2passedict->size[0] && !touch->size[0])
|
||||
continue; // points never interact
|
||||
|
||||
// might intersect, so do an exact clip
|
||||
if (clip->trace.allsolid)
|
||||
return;
|
||||
if (clip->passedict)
|
||||
{
|
||||
if (touch->owner == clip->q2passedict)
|
||||
continue; // don't clip against own missiles
|
||||
if (clip->q2passedict->owner == touch)
|
||||
continue; // don't clip against owner
|
||||
}
|
||||
|
||||
trace = WorldQ2_ClipMoveToEntity (w, touch, clip->start, clip->mins, clip->maxs, clip->end, clip->hitcontentsmask);
|
||||
|
||||
if (trace.allsolid || trace.startsolid ||
|
||||
trace.fraction < clip->trace.fraction)
|
||||
{
|
||||
trace.ent = (edict_t *)touch;
|
||||
clip->trace = trace;
|
||||
}
|
||||
}
|
||||
|
||||
// recurse down both sides
|
||||
if (node->axis == -1)
|
||||
return;
|
||||
|
@ -2127,7 +2452,11 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
|
|||
wedict_t *touch;
|
||||
vec3_t lp;
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
World_ClipToAllLinks (w, &clip);
|
||||
#else
|
||||
World_ClipToLinks (w, w->areanodes, &clip);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < w->maxlagents; i++)
|
||||
{
|
||||
|
@ -2206,7 +2535,13 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef USEAREAGRID
|
||||
World_ClipToAllLinks (w, &clip );
|
||||
#else
|
||||
World_ClipToLinks (w, w->areanodes, &clip );
|
||||
#endif
|
||||
}
|
||||
World_ClipToLinks(w, &w->portallist, &clip);
|
||||
}
|
||||
|
||||
|
@ -2249,12 +2584,7 @@ trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t
|
|||
World_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
|
||||
|
||||
// clip to entities
|
||||
#ifdef Q2BSPS
|
||||
if (w->worldmodel->fromgame == fg_quake2 || w->worldmodel->fromgame == fg_quake3)
|
||||
WorldQ2_ClipMoveToEntities(w, &clip);
|
||||
else
|
||||
#endif
|
||||
WorldQ2_ClipToLinks (w, w->areanodes, &clip );
|
||||
|
||||
return clip.trace;
|
||||
}
|
||||
|
@ -2320,9 +2650,13 @@ void World_Destroy(world_t *world)
|
|||
{
|
||||
World_RBE_Shutdown(world);
|
||||
|
||||
#ifdef USEAREAGRID
|
||||
Z_Free(world->gridareas);
|
||||
#else
|
||||
Z_Free(world->areanodes);
|
||||
world->areanodes = NULL;
|
||||
world->areanodedepth = 0;
|
||||
#endif
|
||||
|
||||
memset(world, 0, sizeof(*world));
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ CC=i686-pc-mingw32-gcc
|
|||
|
||||
all:
|
||||
|
||||
NAMES= fixedemu altwater bloom_blur bloom_filter bloom_final colourtint crepuscular_opaque crepuscular_rays crepuscular_sky depthonly default2d defaultadditivesprite defaultskin defaultsky defaultfill defaultsprite defaultwall defaultwarp defaultgammacb drawflat_wall lpp_depthnorm lpp_light lpp_wall postproc_fisheye postproc_panorama postproc_laea postproc_stereographic postproc_equirectangular fxaa underwaterwarp menutint terrain rtlight
|
||||
NAMES= fixedemu altwater bloom_blur bloom_filter bloom_final colourtint crepuscular_opaque crepuscular_rays crepuscular_sky depthonly default2d defaultadditivesprite defaultskin defaultsky defaultskybox defaultfill defaultsprite defaultwall defaultwarp defaultgammacb drawflat_wall lpp_depthnorm lpp_light lpp_wall postproc_fisheye postproc_panorama postproc_laea postproc_stereographic postproc_equirectangular fxaa underwaterwarp menutint terrain rtlight
|
||||
|
||||
|
||||
ALLNAMES+=$(foreach v,$(NAMES),glsl/$v.glsl)
|
||||
|
|
|
@ -18,6 +18,7 @@ char shaders[][64] =
|
|||
"defaultadditivesprite",
|
||||
"defaultskin",
|
||||
"defaultsky",
|
||||
"defaultskybox",
|
||||
"defaultfill",
|
||||
"defaultsprite",
|
||||
"defaultwall",
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
!!permu SKELETAL
|
||||
!!permu FOG
|
||||
!!permu BUMP
|
||||
!!permu REFLECTCUBEMASK
|
||||
!!cvarf r_glsl_offsetmapping_scale
|
||||
!!cvarf gl_specular
|
||||
!!cvardf gl_affinemodels=0
|
||||
|
@ -36,9 +37,12 @@
|
|||
|
||||
affine varying vec2 tc;
|
||||
varying vec3 light;
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING)
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
varying vec3 eyevector;
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
varying mat3 invsurface;
|
||||
#endif
|
||||
#ifdef TESS
|
||||
varying vec3 vertex;
|
||||
varying vec3 normal;
|
||||
|
@ -46,7 +50,7 @@ varying vec3 normal;
|
|||
|
||||
void main ()
|
||||
{
|
||||
#if defined(SPECULAR)||defined(OFFSETMAPPING)
|
||||
#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
vec3 n, s, t, w;
|
||||
gl_Position = skeletaltransform_wnst(w,n,s,t);
|
||||
vec3 eyeminusvertex = e_eyepos - w.xyz;
|
||||
|
@ -57,6 +61,11 @@ void main ()
|
|||
vec3 n, s, t, w;
|
||||
gl_Position = skeletaltransform_wnst(w,n,s,t);
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
invsurface[0] = s;
|
||||
invsurface[1] = t;
|
||||
invsurface[2] = n;
|
||||
#endif
|
||||
|
||||
tc = v_texcoord;
|
||||
|
||||
|
@ -92,10 +101,14 @@ affine in vec2 tc[];
|
|||
affine out vec2 t_tc[];
|
||||
in vec3 light[];
|
||||
out vec3 t_light[];
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING)
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
in vec3 eyevector[];
|
||||
out vec3 t_eyevector[];
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
in mat3 invsurface[];
|
||||
out mat3 t_invsurface[];
|
||||
#endif
|
||||
void main()
|
||||
{
|
||||
//the control shader needs to pass stuff through
|
||||
|
@ -104,9 +117,14 @@ void main()
|
|||
t_normal[id] = normal[id];
|
||||
t_tc[id] = tc[id];
|
||||
t_light[id] = light[id];
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING)
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
t_eyevector[id] = eyevector[id];
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
t_invsurface[id][0] = invsurface[id][0];
|
||||
t_invsurface[id][1] = invsurface[id][1];
|
||||
t_invsurface[id][2] = invsurface[id][2];
|
||||
#endif
|
||||
|
||||
gl_TessLevelOuter[0] = float(r_tessellation_level);
|
||||
gl_TessLevelOuter[1] = float(r_tessellation_level);
|
||||
|
@ -132,10 +150,14 @@ affine in vec2 t_tc[];
|
|||
affine out vec2 tc;
|
||||
in vec3 t_light[];
|
||||
out vec3 light;
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING)
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
in vec3 t_eyevector[];
|
||||
out vec3 eyevector;
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
in mat3 t_invsurface[];
|
||||
out mat3 invsurface;
|
||||
#endif
|
||||
|
||||
#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2])
|
||||
void main()
|
||||
|
@ -151,9 +173,14 @@ void main()
|
|||
|
||||
//FIXME: we should be recalcing these here, instead of just lerping them
|
||||
light = LERP(t_light);
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING)
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
eyevector = LERP(t_eyevector);
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
invsurface[0] = LERP(t_invsurface[0]);
|
||||
invsurface[1] = LERP(t_invsurface[1]);
|
||||
invsurface[2] = LERP(t_invsurface[2]);
|
||||
#endif
|
||||
|
||||
gl_Position = m_modelviewprojection * vec4(w,1.0);
|
||||
}
|
||||
|
@ -187,9 +214,12 @@ uniform sampler2D s_colourmap;
|
|||
|
||||
affine varying vec2 tc;
|
||||
varying vec3 light;
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING)
|
||||
#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)
|
||||
varying vec3 eyevector;
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
varying mat3 invsurface;
|
||||
#endif
|
||||
|
||||
|
||||
void main ()
|
||||
|
@ -227,8 +257,17 @@ void main ()
|
|||
vec4 specs = texture2D(s_specular, tc);
|
||||
|
||||
vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0));
|
||||
float spec = pow(max(dot(halfdir, bumps), 0.0), 32.0 * specs.a);
|
||||
col.rgb += cvar_gl_specular * spec * specs.rgb;
|
||||
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);
|
||||
#endif
|
||||
|
||||
#ifdef REFLECTCUBEMASK
|
||||
vec3 rtc = reflect(-eyevector, bumps);
|
||||
rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];
|
||||
rtc = (m_model * vec4(rtc.xyz,0.0)).xyz;
|
||||
col.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;
|
||||
#endif
|
||||
|
||||
col.rgb *= light;
|
||||
|
@ -236,7 +275,7 @@ void main ()
|
|||
#ifdef FULLBRIGHT
|
||||
vec4 fb = texture2D(s_fullbright, tc);
|
||||
// col.rgb = mix(col.rgb, fb.rgb, fb.a);
|
||||
col.rgb += fb.rgb * fb.a;
|
||||
col.rgb += fb.rgb * fb.a * e_glowmod.rgb;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
23
engine/shaders/glsl/defaultskybox.glsl
Normal file
23
engine/shaders/glsl/defaultskybox.glsl
Normal file
|
@ -0,0 +1,23 @@
|
|||
!!permu FOG
|
||||
!!samps reflectcube
|
||||
#include "sys/defs.h"
|
||||
#include "sys/fog.h"
|
||||
|
||||
//simple shader for simple skyboxes.
|
||||
|
||||
varying vec3 pos;
|
||||
#ifdef VERTEX_SHADER
|
||||
void main ()
|
||||
{
|
||||
pos = v_position.xyz - e_eyepos;
|
||||
pos.y = -pos.y;
|
||||
gl_Position = ftetransform();
|
||||
}
|
||||
#endif
|
||||
#ifdef FRAGMENT_SHADER
|
||||
void main ()
|
||||
{
|
||||
vec4 skybox = textureCube(s_reflectcube, pos);
|
||||
gl_FragColor = vec4(fog3(skybox.rgb), 1.0);
|
||||
}
|
||||
#endif
|
|
@ -24,7 +24,7 @@
|
|||
varying vec3 eyevector;
|
||||
#endif
|
||||
|
||||
#ifdef REFLECTCUBEMASK
|
||||
#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE)
|
||||
varying mat3 invsurface;
|
||||
#endif
|
||||
|
||||
|
@ -54,7 +54,7 @@ void main ()
|
|||
eyevector.y = dot(eyeminusvertex, v_tvector.xyz);
|
||||
eyevector.z = dot(eyeminusvertex, v_normal.xyz);
|
||||
#endif
|
||||
#ifdef REFLECTCUBEMASK
|
||||
#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE)
|
||||
invsurface[0] = v_svector;
|
||||
invsurface[1] = v_tvector;
|
||||
invsurface[2] = v_normal;
|
||||
|
@ -275,8 +275,10 @@ void main ()
|
|||
#else
|
||||
vec3 lightmaps = vc.rgb;
|
||||
#endif
|
||||
#define delux vec3(0.0,0.0,1.0)
|
||||
#else
|
||||
#ifdef LIGHTSTYLED
|
||||
#define delux vec3(0.0,0.0,1.0)
|
||||
vec3 lightmaps;
|
||||
#ifdef DELUXE
|
||||
lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb * dot(norm, 2.0*texture2D(s_deluxmap0, lm0).rgb-0.5);
|
||||
|
@ -293,9 +295,15 @@ void main ()
|
|||
vec3 lightmaps = (texture2D(s_lightmap, lm0) * e_lmscale).rgb;
|
||||
//modulate by the bumpmap dot light
|
||||
#ifdef DELUXE
|
||||
vec3 delux = 2.0*(texture2D(s_deluxmap, lm0).rgb-0.5);
|
||||
lightmaps *= 1.0 / max(0.25, delux.z); //counter the darkening from deluxmaps
|
||||
vec3 delux = (texture2D(s_deluxmap, lm0).rgb-0.5);
|
||||
#ifdef BUMPMODELSPACE
|
||||
delux = normalize(delux*invsurface);
|
||||
#else
|
||||
lightmaps *= 2.0 / max(0.25, delux.z); //counter the darkening from deluxmaps
|
||||
#endif
|
||||
lightmaps *= dot(norm, delux);
|
||||
#else
|
||||
#define delux vec3(0.0,0.0,1.0)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -303,14 +311,9 @@ void main ()
|
|||
//add in specular, if applicable.
|
||||
#ifdef SPECULAR
|
||||
vec4 specs = texture2D(s_specular, tc);
|
||||
#if defined(DELUXE) && !defined(VERTEXLIT)
|
||||
//not lightstyled...
|
||||
vec3 halfdir = normalize(normalize(eyevector) + 2.0*(texture2D(s_deluxmap0, lm0).rgb-0.5)); //this norm should be the deluxemap info instead
|
||||
#else
|
||||
vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0)); //this norm should be the deluxemap info instead
|
||||
#endif
|
||||
float spec = pow(max(dot(halfdir, norm), 0.0), 32.0 * specs.a);
|
||||
spec *= cvar_gl_specular;
|
||||
vec3 halfdir = normalize(normalize(eyevector) + delux); //this norm should be the deluxemap info instead
|
||||
float spec = pow(max(dot(halfdir, norm), 0.0), 2.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.
|
||||
|
@ -345,10 +348,19 @@ void main ()
|
|||
//entity modifiers
|
||||
gl_FragColor = gl_FragColor * e_colourident;
|
||||
|
||||
#if defined(MASK)
|
||||
#if defined(MASKLT)
|
||||
if (gl_FragColor.a < MASK)
|
||||
discard;
|
||||
#else
|
||||
if (gl_FragColor.a >= MASK)
|
||||
discard;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//and finally hide it all if we're fogged.
|
||||
#ifdef FOG
|
||||
gl_FragColor = fog4(gl_FragColor);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -281,7 +281,7 @@ void main ()
|
|||
|
||||
#ifdef SPECULAR
|
||||
vec3 halfdir = normalize(normalize(eyevector) + nl);
|
||||
float spec = pow(max(dot(halfdir, bumps), 0.0), 32.0 * specs.a);
|
||||
float spec = pow(max(dot(halfdir, bumps), 0.0), FTE_SPECULAR_EXPONENT * specs.a)*float(SPECMUL);
|
||||
diff += l_lightcolourscale.z * spec * specs.rgb;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ struct v2f
|
|||
|
||||
SamplerState SampleType;
|
||||
|
||||
//uniform vec4 e_colourident;
|
||||
float4 main (v2f inp) : SV_TARGET
|
||||
{
|
||||
float4 col;
|
||||
|
@ -69,10 +68,12 @@ struct v2f
|
|||
#endif
|
||||
col.rgb *= inp.light;
|
||||
//#ifdef FULLBRIGHT
|
||||
float4 fb = t_fullbright.Sample(SampleType, inp.tc);
|
||||
col.rgb = lerp(col.rgb, fb.rgb, fb.a);
|
||||
float4 fb = t_fullbright.Sample(SampleType, inp.tc)*e_glowmod;
|
||||
// col.rgb = lerp(col.rgb, fb.rgb, fb.a); //matches vanilla quake...
|
||||
col.rgb += fb.rgb * fb.a; //but nothing expects it to.
|
||||
//#endif
|
||||
col *= e_colourmod;
|
||||
// col = fog4(col);
|
||||
return col;
|
||||
// return fog4(col * e_colourident);
|
||||
}
|
||||
#endif
|
||||
|
|
39
engine/shaders/hlsl11/defaultskybox.hlsl
Normal file
39
engine/shaders/hlsl11/defaultskybox.hlsl
Normal file
|
@ -0,0 +1,39 @@
|
|||
!!samps reflectcube
|
||||
|
||||
//regular sky shader for scrolling q1 skies
|
||||
//the sky surfaces are thrown through this as-is.
|
||||
|
||||
struct a2v
|
||||
{
|
||||
float4 pos: POSITION;
|
||||
};
|
||||
struct v2f
|
||||
{
|
||||
float4 pos: SV_POSITION;
|
||||
float3 texc: TEXCOORD0;
|
||||
};
|
||||
|
||||
#include <ftedefs.h>
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
v2f main (a2v inp)
|
||||
{
|
||||
v2f outp;
|
||||
outp.pos = mul(m_model, inp.pos);
|
||||
outp.texc= outp.pos.xyz - v_eyepos;
|
||||
outp.texc.y = -outp.texc.y;
|
||||
outp.pos = mul(m_view, outp.pos);
|
||||
outp.pos = mul(m_projection, outp.pos);
|
||||
return outp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
TextureCube t_reflectcube : register(t0);
|
||||
SamplerState s_reflectcube : register(s0);
|
||||
|
||||
float4 main (v2f inp) : SV_TARGET
|
||||
{
|
||||
return t_reflectcube.Sample(s_reflectcube, inp.texc);
|
||||
}
|
||||
#endif
|
|
@ -25,10 +25,6 @@
|
|||
float e_time;
|
||||
float3 e_eyepos;
|
||||
|
||||
float l_lightradius;
|
||||
float3 l_lightcolour;
|
||||
float3 l_lightposition;
|
||||
|
||||
sampler s_diffuse; /*diffuse*/
|
||||
sampler s_fullbright; /*normal*/
|
||||
float4 main (v2f inp) : COLOR0
|
||||
|
|
32
engine/shaders/hlsl9/defaultskybox.hlsl
Normal file
32
engine/shaders/hlsl9/defaultskybox.hlsl
Normal file
|
@ -0,0 +1,32 @@
|
|||
struct a2v
|
||||
{
|
||||
float4 pos: POSITION;
|
||||
};
|
||||
struct v2f
|
||||
{
|
||||
#ifndef FRAGMENT_SHADER
|
||||
float4 pos: POSITION;
|
||||
#endif
|
||||
float3 texc: TEXCOORD0;
|
||||
};
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
float3 e_eyepos;
|
||||
float4x4 m_modelviewprojection;
|
||||
v2f main (a2v inp)
|
||||
{
|
||||
v2f outp;
|
||||
outp.pos = mul(m_modelviewprojection, inp.pos);
|
||||
outp.texc= inp.pos - e_eyepos;
|
||||
outp.texc.y = -outp.texc;
|
||||
return outp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
sampler s_reflectcube;
|
||||
float4 main (v2f inp) : COLOR0
|
||||
{
|
||||
return texCUBE(s_reflectcube, inp.texc);
|
||||
}
|
||||
#endif
|
30
engine/shaders/vulkan/default2d.glsl
Normal file
30
engine/shaders/vulkan/default2d.glsl
Normal file
|
@ -0,0 +1,30 @@
|
|||
!!argb PREMUL=false
|
||||
!!samps 1
|
||||
#include "sys/defs.h"
|
||||
|
||||
//this shader is present for support for gles/gl3core contexts
|
||||
//it is single-texture-with-vertex-colours, and doesn't do anything special.
|
||||
//beware that a few things use this, including apparently fonts and bloom rescaling.
|
||||
//its really not meant to do anything special.
|
||||
|
||||
layout(location=0) varying vec2 tc;
|
||||
layout(location=1) varying vec4 vc;
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
void main ()
|
||||
{
|
||||
tc = v_texcoord;
|
||||
vc = v_colour;
|
||||
gl_Position = ftetransform();
|
||||
}
|
||||
#endif
|
||||
#ifdef FRAGMENT_SHADER
|
||||
void main ()
|
||||
{
|
||||
vec4 f = vc;
|
||||
if (arg_PREMUL)
|
||||
f.rgb *= f.a;
|
||||
f *= texture2D(s_t0, tc);
|
||||
gl_FragColor = f;
|
||||
}
|
||||
#endif
|
|
@ -4,11 +4,12 @@
|
|||
//!!permu SKELETAL
|
||||
!!permu FOG
|
||||
!!permu BUMP
|
||||
!!permu REFLECTCUBEMASK
|
||||
!!cvarf r_glsl_offsetmapping=0
|
||||
!!cvarf r_glsl_offsetmapping_scale=0.04
|
||||
!!cvarf gl_specular=0
|
||||
!!cvarb r_fog_exp2=true
|
||||
!!samps diffuse normalmap upper lower specular fullbright
|
||||
!!samps diffuse normalmap upper lower specular fullbright reflectcube reflectmask
|
||||
|
||||
#include "sys/defs.h"
|
||||
|
||||
|
@ -21,6 +22,7 @@ layout(location=1) varying vec3 light;
|
|||
#if defined(SPECULAR) || defined(OFFSETMAPPING)
|
||||
layout(location=2) varying vec3 eyevector;
|
||||
#endif
|
||||
layout(location=3) varying mat3 invsurface;
|
||||
|
||||
|
||||
|
||||
|
@ -30,7 +32,7 @@ layout(location=2) varying vec3 eyevector;
|
|||
void main ()
|
||||
{
|
||||
vec3 n;
|
||||
if (SPECULAR||OFFSETMAPPING)
|
||||
if (SPECULAR||OFFSETMAPPING||REFLECTCUBEMASK)
|
||||
{
|
||||
vec3 s, t, w;
|
||||
gl_Position = skeletaltransform_wnst(w,n,s,t);
|
||||
|
@ -38,6 +40,13 @@ void main ()
|
|||
eyevector.x = dot(eyeminusvertex, s.xyz);
|
||||
eyevector.y = dot(eyeminusvertex, t.xyz);
|
||||
eyevector.z = dot(eyeminusvertex, n.xyz);
|
||||
|
||||
if (REFLECTCUBEMASK)
|
||||
{
|
||||
invsurface[0] = s;
|
||||
invsurface[0] = t;
|
||||
invsurface[0] = n;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -77,9 +86,10 @@ void main ()
|
|||
col.rgb += lc.rgb*e_lowercolour*lc.a;
|
||||
}
|
||||
|
||||
vec3 bumps = vec3(0,0,1);
|
||||
if (BUMP || SPECULAR)
|
||||
{
|
||||
vec3 bumps = normalize(vec3(texture2D(s_normalmap, tc)) - 0.5);
|
||||
bumps = normalize(vec3(texture2D(s_normalmap, tc)) - 0.5);
|
||||
vec4 specs = texture2D(s_specular, tc);
|
||||
|
||||
vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0));
|
||||
|
@ -87,6 +97,14 @@ void main ()
|
|||
col.rgb += cvar_gl_specular * spec * specs.rgb;
|
||||
}
|
||||
|
||||
if (REFLECTCUBEMASK)
|
||||
{
|
||||
vec3 rtc = reflect(-eyevector, bumps);
|
||||
rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];
|
||||
rtc = (m_model * vec4(rtc.xyz,0.0)).xyz;
|
||||
col.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;
|
||||
}
|
||||
|
||||
col.rgb *= light;
|
||||
|
||||
if (FULLBRIGHT)
|
||||
|
|
24
engine/shaders/vulkan/defaultskybox.glsl
Normal file
24
engine/shaders/vulkan/defaultskybox.glsl
Normal file
|
@ -0,0 +1,24 @@
|
|||
!!permu FOG
|
||||
!!samps reflectcube
|
||||
!!cvarb r_fog_exp2=true
|
||||
#include "sys/defs.h"
|
||||
#include "sys/fog.h"
|
||||
|
||||
//simple shader for simple skyboxes.
|
||||
|
||||
varying vec3 pos;
|
||||
#ifdef VERTEX_SHADER
|
||||
void main ()
|
||||
{
|
||||
pos = v_position.xyz - e_eyepos;
|
||||
pos.y = -pos.y;
|
||||
gl_Position = ftetransform();
|
||||
}
|
||||
#endif
|
||||
#ifdef FRAGMENT_SHADER
|
||||
void main ()
|
||||
{
|
||||
vec4 skybox = textureCube(s_reflectcube, pos);
|
||||
gl_FragColor = vec4(fog3(skybox.rgb), 1.0);
|
||||
}
|
||||
#endif
|
|
@ -10,6 +10,8 @@
|
|||
!!argb vertexlit=0
|
||||
!!samps paletted 1
|
||||
!!argb eightbit=0
|
||||
!!argf mask=1.0
|
||||
!!argb masklt=false
|
||||
!!permu FOG
|
||||
//!!permu DELUXE
|
||||
//!!permu LIGHTSTYLED //this seems to be breaking nvidia drivers if set from the engine, despite us not using it...
|
||||
|
@ -186,6 +188,20 @@ void main ()
|
|||
//entity modifiers
|
||||
gl_FragColor = gl_FragColor * e_colourident;
|
||||
|
||||
if (arg_mask != 1.0)
|
||||
{
|
||||
if (arg_masklt)
|
||||
{
|
||||
if (gl_FragColor.a < arg_mask)
|
||||
discard;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gl_FragColor.a >= arg_mask)
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
||||
//and finally hide it all if we're fogged.
|
||||
#ifdef FOG
|
||||
gl_FragColor = fog4(gl_FragColor);
|
||||
|
|
|
@ -160,7 +160,7 @@ typedef struct
|
|||
vec3_t l_lightcolourscale; float l_lightradius;
|
||||
vec4_t l_shadowmapproj;
|
||||
vec2_t l_shadowmapscale; vec2_t pad3;
|
||||
} cbuf_light_t;
|
||||
} vkcbuf_light_t;
|
||||
|
||||
//entity-specific constant-buffer
|
||||
typedef struct
|
||||
|
@ -180,7 +180,7 @@ typedef struct
|
|||
vec4_t e_colourident;
|
||||
vec4_t w_fogcolours;
|
||||
float w_fogdensity; float w_fogdepthbias; vec2_t pad7;
|
||||
} cbuf_entity_t;
|
||||
} vkcbuf_entity_t;
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -3094,6 +3094,8 @@ static qboolean BE_SetupMeshProgram(program_t *p, shaderpass_t *pass, unsigned i
|
|||
perm |= PERMUTATION_FULLBRIGHT;
|
||||
if (TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))
|
||||
perm |= PERMUTATION_UPPERLOWER;
|
||||
if (TEXLOADED(shaderstate.curtexnums->reflectcube) || TEXLOADED(shaderstate.curtexnums->reflectmask))
|
||||
perm |= PERMUTATION_REFLECTCUBEMASK;
|
||||
if (r_refdef.globalfog.density)
|
||||
perm |= PERMUTATION_FOG;
|
||||
// if (r_glsl_offsetmapping.ival && TEXLOADED(shaderstate.curtexnums->bump))
|
||||
|
@ -4166,7 +4168,7 @@ batch_t *VKBE_GetTempBatch(void)
|
|||
void VKBE_SetupLightCBuffer(dlight_t *l, vec3_t colour)
|
||||
{
|
||||
extern cvar_t gl_specular;
|
||||
cbuf_light_t *cbl = VKBE_AllocateBufferSpace(DB_UBO, (sizeof(*cbl) + 0x0ff) & ~0xff, &shaderstate.ubo_light.buffer, &shaderstate.ubo_light.offset);
|
||||
vkcbuf_light_t *cbl = VKBE_AllocateBufferSpace(DB_UBO, (sizeof(*cbl) + 0x0ff) & ~0xff, &shaderstate.ubo_light.buffer, &shaderstate.ubo_light.offset);
|
||||
shaderstate.ubo_light.range = sizeof(*cbl);
|
||||
|
||||
if (!l)
|
||||
|
@ -4216,7 +4218,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod)
|
|||
float ndr;
|
||||
float modelmatrix[16];
|
||||
float *m = modelmatrix;
|
||||
cbuf_entity_t *cbe = VKBE_AllocateBufferSpace(DB_UBO, (sizeof(*cbe) + 0x0ff) & ~0xff, &shaderstate.ubo_entity.buffer, &shaderstate.ubo_entity.offset);
|
||||
vkcbuf_entity_t *cbe = VKBE_AllocateBufferSpace(DB_UBO, (sizeof(*cbe) + 0x0ff) & ~0xff, &shaderstate.ubo_entity.buffer, &shaderstate.ubo_entity.offset);
|
||||
shaderstate.ubo_entity.range = sizeof(*cbe);
|
||||
|
||||
shaderstate.curentity = e;
|
||||
|
@ -5163,12 +5165,13 @@ static void BE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
|
||||
if (batch->shader->flags & SHADER_SKY)
|
||||
{
|
||||
if (!batch->shader->prog)
|
||||
if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK)
|
||||
{
|
||||
if (shaderstate.mode == BEM_STANDARD)
|
||||
R_DrawSkyChain (batch);
|
||||
if (R_DrawSkyChain (batch))
|
||||
continue;
|
||||
}
|
||||
else if (shaderstate.mode != BEM_FOG && shaderstate.mode != BEM_CREPUSCULAR && shaderstate.mode != BEM_WIREFRAME)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((batch->shader->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT | SHADER_HASRIPPLEMAP)) && shaderstate.mode != BEM_WIREFRAME)
|
||||
|
@ -6195,7 +6198,7 @@ void VKBE_DrawWorld (batch_t **worldbatches)
|
|||
shaderstate.identitylighting = r_shadow_realtime_world_lightmaps.value;
|
||||
else
|
||||
#endif
|
||||
shaderstate.identitylighting = 1;
|
||||
shaderstate.identitylighting = r_lightmap_scale.value;
|
||||
shaderstate.identitylighting *= r_refdef.hdr_value;
|
||||
shaderstate.identitylightmap = shaderstate.identitylighting / (1<<gl_overbright.ival);
|
||||
|
||||
|
@ -6214,18 +6217,19 @@ void VKBE_DrawWorld (batch_t **worldbatches)
|
|||
|
||||
|
||||
VKBE_SubmitMeshes(worldbatches, batches, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1);
|
||||
RSpeedEnd(RSPEED_WORLD);
|
||||
RSpeedEnd(RSPEED_OPAQUE);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
RSpeedRemark();
|
||||
VKBE_SelectEntity(&r_worldentity);
|
||||
Sh_DrawLights(r_refdef.scenevis);
|
||||
RSpeedEnd(RSPEED_STENCILSHADOWS);
|
||||
RSpeedEnd(RSPEED_RTLIGHTS);
|
||||
#endif
|
||||
}
|
||||
|
||||
RSpeedRemark();
|
||||
VKBE_SubmitMeshes(worldbatches, batches, SHADER_SORT_SEETHROUGH+1, SHADER_SORT_COUNT);
|
||||
|
||||
RSpeedEnd(RSPEED_TRANSPARENTS);
|
||||
|
||||
if (r_wireframe.ival)
|
||||
{
|
||||
|
@ -6239,7 +6243,7 @@ void VKBE_DrawWorld (batch_t **worldbatches)
|
|||
shaderstate.identitylighting = 1;
|
||||
shaderstate.identitylightmap = 1;
|
||||
VKBE_SubmitMeshes(NULL, batches, SHADER_SORT_PORTAL, SHADER_SORT_COUNT);
|
||||
RSpeedEnd(RSPEED_DRAWENTITIES);
|
||||
RSpeedEnd(RSPEED_TRANSPARENTS);
|
||||
}
|
||||
|
||||
R_RenderDlights ();
|
||||
|
|
|
@ -227,6 +227,7 @@ static void VK_DestroySwapChain(void)
|
|||
VKBE_ShutdownFramePools(frame);
|
||||
|
||||
vkFreeCommandBuffers(vk.device, vk.cmdpool, frame->maxcbufs, frame->cbufs);
|
||||
BZ_Free(frame->cbufs);
|
||||
vkDestroyFence(vk.device, frame->finishedfence, vkallocationcb);
|
||||
Z_Free(frame);
|
||||
}
|
||||
|
@ -3520,10 +3521,11 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
|
|||
if (j == queue_count)
|
||||
{
|
||||
//no queues can present to that surface, so I guess we can't use that device
|
||||
Con_DPrintf("vulkan: ignoring device %s as it can't present to window\n", props.deviceName);
|
||||
Con_DPrintf("vulkan: ignoring device \"%s\" as it can't present to window\n", props.deviceName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Con_DPrintf("Found Vulkan Device \"%s\"\n", props.deviceName);
|
||||
|
||||
if (!vk.gpu)
|
||||
vk.gpu = devs[i];
|
||||
|
@ -3848,6 +3850,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
|
|||
sh_config.env_add = false; //fixme: figure out what this means...
|
||||
|
||||
sh_config.can_mipcap = true;
|
||||
sh_config.havecubemaps = true;
|
||||
|
||||
VK_CheckTextureFormats();
|
||||
|
||||
|
|
Loading…
Reference in a new issue