code to use occlusion queries for coronas.
tweaked cl_maxfps a little. now sticks much closer to the desired rate. also tweaked cl_netfps. clamps 77fps to 13ms frames (read: 76.9 fps) in an attempt to avoid tripping up any framerate checks (we had previously been using a lower net rate with occasional 14ms frames). viewspace particles are now a thing. greater control over spawning particles. its now possible to spawn particles only in slime, etc. fix soundlength builtin. preliminary version of r_dynamic -1, which can give some significant framerate boosts on certain maps. fix halflife bsp texture issues. rewrote worker thread logic. workers now work as a single pool, instead of independent pools. this means that you don't have to wait for a specific thread to finish before it can load new stuff, reducing overall load times some more. worker_count cvar allows reconfiguring the number of active workers. can be changed any time. updated mod_terrain_create command. should be more useful now and make more sense when first loaded. fix lit support. apparently its been broken for a while. brush editor now has csg subtraction. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4990 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
cc875358fd
commit
5172823341
76 changed files with 2964 additions and 877 deletions
|
@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "quakedef.h"
|
||||
#include "particles.h"
|
||||
#include "shader.h"
|
||||
#include "glquake.h"
|
||||
|
||||
extern cvar_t cl_predict_players;
|
||||
extern cvar_t cl_predict_players_frac;
|
||||
|
@ -100,8 +101,13 @@ void CL_FreeDlights(void)
|
|||
int i;
|
||||
if (cl_dlights)
|
||||
for (i = 0; i < rtlights_max; i++)
|
||||
{
|
||||
if (cl_dlights[i].worldshadowmesh)
|
||||
SH_FreeShadowMesh(cl_dlights[i].worldshadowmesh);
|
||||
|
||||
if (cl_dlights[i].coronaocclusionquery)
|
||||
qglDeleteQueriesARB(1, &cl_dlights[i].coronaocclusionquery);
|
||||
}
|
||||
#endif
|
||||
|
||||
rtlights_max = cl_maxdlights = 0;
|
||||
|
@ -110,6 +116,7 @@ void CL_FreeDlights(void)
|
|||
}
|
||||
void CL_InitDlights(void)
|
||||
{
|
||||
CL_FreeDlights();
|
||||
rtlights_max = cl_maxdlights = RTL_FIRST;
|
||||
cl_dlights = BZ_Realloc(cl_dlights, sizeof(*cl_dlights)*cl_maxdlights);
|
||||
memset(cl_dlights, 0, sizeof(*cl_dlights)*cl_maxdlights);
|
||||
|
@ -117,9 +124,12 @@ void CL_InitDlights(void)
|
|||
|
||||
static void CL_ClearDlight(dlight_t *dl, int key)
|
||||
{
|
||||
void *sm;
|
||||
sm = dl->worldshadowmesh;
|
||||
void *sm = dl->worldshadowmesh;
|
||||
unsigned int oq = dl->coronaocclusionquery;
|
||||
unsigned int oqr = (dl->key == key)?dl->coronaocclusionresult:false;
|
||||
memset (dl, 0, sizeof(*dl));
|
||||
dl->coronaocclusionquery = oq;
|
||||
dl->coronaocclusionresult = oqr;
|
||||
dl->rebuildcache = true;
|
||||
dl->worldshadowmesh = sm;
|
||||
dl->axis[0][0] = 1;
|
||||
|
@ -222,12 +232,6 @@ dlight_t *CL_NewDlight (int key, const vec3_t org, float radius, float time,
|
|||
return dl;
|
||||
}
|
||||
|
||||
dlight_t *CL_NewDlightRGB(int key, const vec3_t org, float radius, float time,
|
||||
float r, float g, float b)
|
||||
{
|
||||
return CL_NewDlight(key, org, radius, time, r*5, g*5, b*5);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
|
@ -1911,7 +1915,7 @@ void VQ2_AddLerpEntity(entity_t *in) //a convienience function
|
|||
*/
|
||||
int V_AddLight (int entsource, vec3_t org, float quant, float r, float g, float b)
|
||||
{
|
||||
return CL_NewDlightRGB (entsource, org, quant, -0.1, r, g, b) - cl_dlights;
|
||||
return CL_NewDlight (entsource, org, quant, -0.1, r*5, g*5, b*5) - cl_dlights;
|
||||
}
|
||||
|
||||
void CLQ1_AddOrientedHalfSphere(shader_t *shader, float radius, float gap, float *matrix, float r, float g, float b, float a)
|
||||
|
@ -2290,7 +2294,7 @@ void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qbo
|
|||
{
|
||||
// int oldents = cl_numvisedicts;
|
||||
// cl_numvisedicts = 0;
|
||||
BE_DrawWorld(false, NULL);
|
||||
BE_DrawWorld(NULL, NULL);
|
||||
cl_numstris = 0;
|
||||
// cl_numvisedicts = oldents;
|
||||
}
|
||||
|
@ -2938,7 +2942,7 @@ void CL_LinkStaticEntities(void *pvs)
|
|||
model_t *clmodel;
|
||||
extern cvar_t r_drawflame, gl_part_flame;
|
||||
|
||||
if (r_drawflame.ival < 0)
|
||||
if (r_drawflame.ival < 0 || r_drawentities.ival == 0)
|
||||
return;
|
||||
|
||||
if (!cl.worldmodel)
|
||||
|
|
|
@ -31,6 +31,7 @@ static void QDECL CL_SpareMsec_Callback (struct cvar_s *var, char *oldvalue);
|
|||
|
||||
cvar_t cl_nodelta = CVAR("cl_nodelta","0");
|
||||
|
||||
cvar_t cl_c2sdupe = CVAR("cl_c2sdupe", "0");
|
||||
cvar_t cl_c2spps = CVAR("cl_c2spps", "0");
|
||||
cvar_t cl_c2sImpulseBackup = SCVAR("cl_c2sImpulseBackup","3");
|
||||
cvar_t cl_netfps = CVAR("cl_netfps", "150");
|
||||
|
@ -1177,10 +1178,16 @@ float CL_FilterTime (double time, float wantfps, qboolean ignoreserver) //now re
|
|||
fps = bound (6.7, wantfps, fpscap); //we actually cap ourselves to 150msecs (1000/7 = 142)
|
||||
}
|
||||
|
||||
//its not time yet
|
||||
if (time < ceil(1000 / fps))
|
||||
return 0;
|
||||
|
||||
return time - ceil(1000 / fps);
|
||||
//clamp it if we have over 1.5 frame banked somehow
|
||||
if (time - (1000 / fps) > (1000 / fps)*1.5)
|
||||
return (1000 / fps) * 1.5;
|
||||
|
||||
//report how much spare time the caller now has
|
||||
return time - (1000 / fps);
|
||||
}
|
||||
|
||||
qboolean allowindepphys;
|
||||
|
@ -1320,10 +1327,6 @@ int CL_IndepPhysicsThread(void *param)
|
|||
spare = CL_FilterTime((time - lasttime)*1000, cl_netfps.value, false);
|
||||
if (spare)
|
||||
{
|
||||
//don't let them bank too much and get sudden bursts
|
||||
if (spare > 15)
|
||||
spare = 15;
|
||||
|
||||
time -= spare/1000.0f;
|
||||
Sys_LockMutex(indeplock);
|
||||
if (cls.state)
|
||||
|
@ -1529,7 +1532,8 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend)
|
|||
|
||||
cmd->lightlevel = 0;
|
||||
#ifdef CSQC_DAT
|
||||
CSQC_Input_Frame(plnum, cmd);
|
||||
if (!runningindepphys)
|
||||
CSQC_Input_Frame(plnum, cmd);
|
||||
#endif
|
||||
memset(&independantphysics[plnum], 0, sizeof(independantphysics[plnum]));
|
||||
}
|
||||
|
@ -1631,8 +1635,10 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
static float pps_balance = 0;
|
||||
static int dropcount = 0;
|
||||
static double msecs;
|
||||
static double msecsround;
|
||||
int msecstouse;
|
||||
qboolean dontdrop=false;
|
||||
float usetime;
|
||||
|
||||
clcmdbuf_t *next;
|
||||
|
||||
|
@ -1739,39 +1745,28 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
#ifdef IRCCONNECT
|
||||
if (cls.netchan.remote_address.type != NA_IRC)
|
||||
#endif
|
||||
if (msecs>150) //q2 has 200 slop.
|
||||
msecs=150;
|
||||
|
||||
msecs += frametime*1000;
|
||||
// Con_Printf("%f\n", msecs);
|
||||
|
||||
if (msecs<0)
|
||||
msecs=0; //erm.
|
||||
|
||||
msecstouse = (int)msecs; //casts round down.
|
||||
if (msecstouse == 0)
|
||||
return;
|
||||
#ifdef IRCCONNECT
|
||||
if (cls.netchan.remote_address.type != NA_IRC)
|
||||
#endif
|
||||
if (msecstouse > 200) // cap at 200 to avoid servers splitting movement more than four times
|
||||
msecstouse = 200;
|
||||
|
||||
// align msecstouse to avoid servers wasting our msecs
|
||||
if (msecstouse > 100)
|
||||
msecstouse &= ~3; // align to 4
|
||||
else if (msecstouse > 50)
|
||||
msecstouse &= ~1; // align to 2
|
||||
|
||||
wantfps = cl_netfps.value;
|
||||
fullsend = true;
|
||||
|
||||
msecstouse = 0;
|
||||
|
||||
#ifndef CLIENTONLY
|
||||
if (sv.state && cls.state != ca_active)
|
||||
{
|
||||
fullsend = -1;
|
||||
msecstouse = usetime = msecs;
|
||||
msecs = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!runningindepphys)
|
||||
{
|
||||
// while we're not playing send a slow keepalive fullsend to stop mvdsv from screwing up
|
||||
if (cls.state < ca_active && !cls.download)
|
||||
|
@ -1783,23 +1778,42 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
#endif
|
||||
wantfps = 12.5;
|
||||
}
|
||||
if (cl_netfps.value > 0 || !fullsend)
|
||||
if (!runningindepphys && (cl_netfps.value > 0 || !fullsend))
|
||||
{
|
||||
float spare;
|
||||
spare = CL_FilterTime(msecstouse, wantfps, false);
|
||||
if (!spare && (msecstouse < 200
|
||||
#ifdef IRCCONNECT
|
||||
|| cls.netchan.remote_address.type == NA_IRC
|
||||
#endif
|
||||
))
|
||||
spare = CL_FilterTime(msecs, wantfps, false);
|
||||
usetime = msecsround + (msecs - spare);
|
||||
msecstouse = (int)usetime;
|
||||
if (!spare)
|
||||
fullsend = false;
|
||||
if (spare > cl_sparemsec.ival)
|
||||
spare = cl_sparemsec.ival;
|
||||
if (spare > 0)
|
||||
msecstouse -= spare;
|
||||
else
|
||||
{
|
||||
msecsround = usetime - msecstouse;
|
||||
msecs = spare + msecstouse;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
usetime = msecsround + msecs;
|
||||
msecstouse = (int)usetime;
|
||||
msecsround = usetime - msecstouse;
|
||||
}
|
||||
}
|
||||
|
||||
if (msecstouse > 200) // cap at 200 to avoid servers splitting movement more than four times
|
||||
msecstouse = 200;
|
||||
|
||||
// align msecstouse to avoid servers wasting our msecs
|
||||
if (msecstouse > 100)
|
||||
msecstouse &= ~3; // align to 4
|
||||
else if (msecstouse > 50)
|
||||
msecstouse &= ~1; // align to 2
|
||||
|
||||
if (msecstouse < 0) //FIXME
|
||||
fullsend = false;
|
||||
if (usetime <= 0)
|
||||
return; //infinite frame times = weirdness.
|
||||
|
||||
#ifdef HLCLIENT
|
||||
if (!CLHL_BuildUserInput(msecstouse, &independantphysics[0]))
|
||||
#endif
|
||||
|
@ -1829,7 +1843,12 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
// if (cl.spectator)
|
||||
Cam_Track(&cl.playerview[plnum], &independantphysics[plnum]);
|
||||
Cam_FinishMove(&cl.playerview[plnum], &independantphysics[plnum]);
|
||||
independantphysics[plnum].msec = msecstouse;
|
||||
independantphysics[plnum].msec = usetime;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
//the main loop isn't allowed to send
|
||||
|
@ -1839,9 +1858,12 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
// if (skipcmd)
|
||||
// return;
|
||||
|
||||
if (!fullsend || !msecstouse)
|
||||
if (!fullsend)
|
||||
return; // when we're actually playing we try to match netfps exactly to avoid gameplay problems
|
||||
|
||||
if (msecstouse == 12)
|
||||
msecstouse = 13;
|
||||
|
||||
// if (msecstouse > 127)
|
||||
// Con_Printf("%i\n", msecstouse, msecs);
|
||||
|
||||
|
@ -2003,6 +2025,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
|
|||
//
|
||||
// deliver the message
|
||||
//
|
||||
cls.netchan.dupe = cl_c2sdupe.ival;
|
||||
Netchan_Transmit (&cls.netchan, buf.cursize, buf.data, 2500);
|
||||
|
||||
if (cls.netchan.fatal_error)
|
||||
|
@ -2051,6 +2074,7 @@ void CL_InitInput (void)
|
|||
|
||||
Cvar_Register (&prox_inmenu, inputnetworkcvargroup);
|
||||
|
||||
Cvar_Register (&cl_c2sdupe, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_c2sImpulseBackup, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_c2spps, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_queueimpulses, inputnetworkcvargroup);
|
||||
|
|
|
@ -4861,8 +4861,8 @@ double Host_Frame (double time)
|
|||
)
|
||||
{
|
||||
// realtime += spare/1000; //don't use it all!
|
||||
spare = CL_FilterTime((realtime - oldrealtime)*1000, maxfps, maxfpsignoreserver);
|
||||
if (!spare)
|
||||
double newspare = CL_FilterTime((spare/1000 + realtime - oldrealtime)*1000, maxfps, maxfpsignoreserver);
|
||||
if (!newspare)
|
||||
{
|
||||
while(COM_DoWork(0, false))
|
||||
;
|
||||
|
@ -4872,6 +4872,7 @@ double Host_Frame (double time)
|
|||
spare = 0; //uncapped.
|
||||
if (spare > cl_sparemsec.ival)
|
||||
spare = cl_sparemsec.ival;
|
||||
spare = newspare;
|
||||
|
||||
// realtime -= spare/1000; //don't use it all!
|
||||
}
|
||||
|
@ -4889,7 +4890,7 @@ double Host_Frame (double time)
|
|||
CL_ProgressDemoTime();
|
||||
hadwork = haswork;
|
||||
}
|
||||
cl.stillloading = cl.sendprespawn || (cls.state < ca_active && COM_HasWork());
|
||||
cl.stillloading = cl.sendprespawn || (cls.state < ca_active && worker_flush.ival && COM_HasWork());
|
||||
COM_MainThreadWork();
|
||||
|
||||
|
||||
|
|
|
@ -5835,7 +5835,7 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n
|
|||
{
|
||||
flocation_t loc;
|
||||
Cmd_TokenizeString(stufftext+2, false, false);
|
||||
if (FS_FLocateFile(Cmd_Argv(1), FSLFRT_IFFOUND, &loc))
|
||||
if (FS_FLocateFile(Cmd_Argv(1), FSLF_IFFOUND, &loc))
|
||||
Con_Printf("You have been kicked due to the file \"%s\" being modified.\n", Cmd_Argv(1));
|
||||
}
|
||||
#ifdef PLUGINS
|
||||
|
@ -6568,13 +6568,13 @@ void CLQW_ParseServerMessage (void)
|
|||
|
||||
case svcfte_cgamepacket:
|
||||
csqcpacket = true;
|
||||
#ifdef CSQC_DAT
|
||||
if (CSQC_ParseGamePacket())
|
||||
break;
|
||||
#endif
|
||||
#ifdef HLCLIENT
|
||||
if (CLHL_ParseGamePacket())
|
||||
break;
|
||||
#endif
|
||||
#ifdef CSQC_DAT
|
||||
if (CSQC_ParseGamePacket())
|
||||
break;
|
||||
#endif
|
||||
Con_Printf("Unable to parse gamecode packet\n");
|
||||
break;
|
||||
|
|
|
@ -1246,7 +1246,6 @@ void CL_PredictMovePNum (int seat)
|
|||
{
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
extern cvar_t temp1;
|
||||
pv->simorg[i] = (1-f)*fromstate->origin[i] + f*tostate->origin[i];
|
||||
pv->simvel[i] = (1-f)*fromstate->velocity[i] + f*tostate->velocity[i];
|
||||
|
||||
|
|
|
@ -1096,6 +1096,7 @@ void CL_ParseTEnt (void)
|
|||
if (nqprot)
|
||||
{
|
||||
//easiest way to handle these
|
||||
//should probably also do qwgunshot ones with nq protocols or something
|
||||
switch(type)
|
||||
{
|
||||
case TENQ_EXPLOSION2:
|
||||
|
@ -1107,10 +1108,41 @@ void CL_ParseTEnt (void)
|
|||
case TE_EXPLOSION:
|
||||
type = TEQW_EXPLOSIONNOSPRITE;
|
||||
break;
|
||||
case TE_GUNSHOT:
|
||||
type = TE_GUNSHOT_NQCOMPAT;
|
||||
break;
|
||||
case TE_GUNSHOT_NQCOMPAT:
|
||||
type = TE_GUNSHOT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//right, nq vs qw doesn't matter now, supposedly.
|
||||
|
||||
if (cl_shownet.ival >= 2)
|
||||
{
|
||||
static char *te_names[] = {
|
||||
"spike", "superspike", "qwgunshot", "qwexplosion",
|
||||
"tarexplosion", "lightning1", "lightning2", "wizspike",
|
||||
"knightspike", "lightning3", "lavasplash", "teleport",
|
||||
"blood", "lightningblood", "bullet", "superbullet", //bullets deprecated
|
||||
"railtrail", "beam", "explosion2", "nqexplosion",
|
||||
"nqgunshot", "?", "?", "?",
|
||||
#ifdef HEXEN2
|
||||
"h2lightsml", "h2chain", "h2sunstf1", "h2sunstf2",
|
||||
"h2light", "h2cb", "h2ic", "h2gaze",
|
||||
"h2famine", "h2partexp"
|
||||
#endif
|
||||
};
|
||||
|
||||
if (type < countof(te_names))
|
||||
Con_Printf(" te_%s\n", te_names[type]);
|
||||
else
|
||||
Con_Printf(" te_%i\n", type);
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TE_WIZSPIKE: // spike hitting wall
|
||||
|
@ -1509,8 +1541,10 @@ void CL_ParseTEnt (void)
|
|||
P_RunParticleEffect (pos, vec3_origin, 0, 20);
|
||||
|
||||
break;
|
||||
|
||||
case TE_GUNSHOT: // bullet hitting wall
|
||||
if (nqprot)
|
||||
case TE_GUNSHOT_NQCOMPAT:
|
||||
if (type == TE_GUNSHOT_NQCOMPAT)
|
||||
cnt = 1;
|
||||
else
|
||||
cnt = MSG_ReadByte ();
|
||||
|
@ -3301,7 +3335,7 @@ fixme:
|
|||
ex = CL_AllocExplosion (pos);
|
||||
ex->flags = Q2RF_FULLBRIGHT|RF_NOSHADOW;
|
||||
ex->start = cl.q2frame.servertime - 100;
|
||||
CL_NewDlightRGB(0, pos, 350, 0.5, 0.2, 0.1, 0);
|
||||
CL_NewDlight(0, pos, 350, 0.5, 0.2*5, 0.1*5, 0*5);
|
||||
P_RunParticleEffectTypeString(pos, NULL, 1, "te_muzzleflash");
|
||||
break;
|
||||
case CRTE_BLUE_MUZZLEFLASH:
|
||||
|
@ -3309,7 +3343,7 @@ fixme:
|
|||
ex = CL_AllocExplosion (pos);
|
||||
ex->flags = Q2RF_FULLBRIGHT|RF_NOSHADOW;
|
||||
ex->start = cl.q2frame.servertime - 100;
|
||||
CL_NewDlightRGB(0, pos, 350, 0.5, 0.2, 0.1, 0);
|
||||
CL_NewDlight(0, pos, 350, 0.5, 0.2*5, 0.1*5, 0*5);
|
||||
P_RunParticleEffectTypeString(pos, NULL, 1, "te_blue_muzzleflash");
|
||||
break;
|
||||
case CRTE_SMART_MUZZLEFLASH:
|
||||
|
@ -3317,7 +3351,7 @@ fixme:
|
|||
ex = CL_AllocExplosion (pos);
|
||||
ex->flags = Q2RF_FULLBRIGHT|RF_NOSHADOW;
|
||||
ex->start = cl.q2frame.servertime - 100;
|
||||
CL_NewDlightRGB(0, pos, 350, 0.5, 0.2, 0, 0.2);
|
||||
CL_NewDlight(0, pos, 350, 0.5, 0.2*5, 0*5, 0.2*5);
|
||||
P_RunParticleEffectTypeString(pos, NULL, 1, "te_smart_muzzleflash");
|
||||
break;
|
||||
case CRTE_LEADERFIELD:
|
||||
|
@ -3328,7 +3362,7 @@ fixme:
|
|||
VectorCopy (pos, ex->origin);
|
||||
ex->flags = Q2RF_FULLBRIGHT|RF_NOSHADOW;
|
||||
ex->start = cl.q2frame.servertime - 100;
|
||||
CL_NewDlightRGB(0, pos, 350, 0.5, 0.2, 0, 0.2);
|
||||
CL_NewDlight(0, pos, 350, 0.5, 0.2*5, 0*5, 0.2*5);
|
||||
P_RunParticleEffectTypeString(pos, NULL, 1, "te_deathfield");
|
||||
break;
|
||||
case CRTE_BLASTERBEAM:
|
||||
|
|
|
@ -309,8 +309,8 @@ typedef struct
|
|||
void (QDECL *player_setkey) (char *key, char *value); //wait, no pnum?
|
||||
|
||||
qboolean (QDECL *getcdkey) (int playernum, char key[16]);
|
||||
int trackerfromplayer;
|
||||
int playerfromtracker;
|
||||
int (QDECL *trackerfromplayer) (int pl);
|
||||
int (QDECL *playerfromtracker) (int tr);
|
||||
int (QDECL *sendcmd_unreliable) (char *cmd);
|
||||
void (QDECL *getsysmousepos) (long *xandy);
|
||||
void (QDECL *setsysmousepos) (int x, int y);
|
||||
|
@ -707,8 +707,8 @@ void QDECL CLGHL_getplayerinfo (int entnum, hlplayerinfo_t *result)
|
|||
result->isus = true;
|
||||
result->isspec = player->spectator;
|
||||
result->pl = player->pl;
|
||||
if (player->skin)
|
||||
result->model = player->skin->name;
|
||||
if (player->qwskin)
|
||||
result->model = player->qwskin->name;
|
||||
else
|
||||
result->model = "";
|
||||
}
|
||||
|
@ -722,7 +722,7 @@ void QDECL CLGHL_startsound_name (char *name, float vol)
|
|||
Con_Printf ("CLGHL_startsound_name: can't cache %s\n", name);
|
||||
return;
|
||||
}
|
||||
S_StartSound (-1, -1, sfx, vec3_origin, vol, 1, 0, 0);
|
||||
S_StartSound (-1, -1, sfx, vec3_origin, vol, 1, 0, 0, 0);
|
||||
}
|
||||
void QDECL CLGHL_startsound_idx (int idx, float vol)
|
||||
{
|
||||
|
@ -733,7 +733,7 @@ void QDECL CLGHL_startsound_idx (int idx, float vol)
|
|||
Con_Printf ("CLGHL_startsound_name: index not precached %s\n", name);
|
||||
return;
|
||||
}
|
||||
S_StartSound (-1, -1, sfx, vec3_origin, vol, 1, 0, 0);
|
||||
S_StartSound (-1, -1, sfx, vec3_origin, vol, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
void QDECL CLGHL_anglevectors (float *ina, float *outf, float *outr, float *outu)
|
||||
|
@ -1175,8 +1175,8 @@ CLHL_enginecgamefuncs_t CLHL_enginecgamefuncs =
|
|||
CLGHL_player_setkey,
|
||||
|
||||
CLGHL_getcdkey,
|
||||
(void*)0xdeaddead,//CLGHL_trackerfromplayer;
|
||||
(void*)0xdeaddead,//CLGHL_playerfromtracker;
|
||||
CLGHL_trackerfromplayer,
|
||||
CLGHL_playerfromtracker,
|
||||
CLGHL_sendcmd_unreliable,
|
||||
CLGHL_getsysmousepos,
|
||||
CLGHL_setsysmousepos,
|
||||
|
@ -1186,7 +1186,7 @@ CLHL_enginecgamefuncs_t CLHL_enginecgamefuncs =
|
|||
0xdeadbeef
|
||||
};
|
||||
|
||||
dllhandle_t clg;
|
||||
dllhandle_t *clg;
|
||||
|
||||
int CLHL_GamecodeDoesMouse(void)
|
||||
{
|
||||
|
@ -1270,7 +1270,8 @@ void CLHL_LoadClientGame(void)
|
|||
|
||||
clg = NULL;
|
||||
iterator = NULL;
|
||||
while(COM_IteratePaths(&iterator, path, sizeof(path)))
|
||||
//FIXME: dlls in gamepaths is evil
|
||||
while(COM_IteratePaths(&iterator, path, sizeof(path), NULL, 0))
|
||||
{
|
||||
snprintf (fullname, sizeof(fullname), "%s%s", path, "cl_dlls/client");
|
||||
clg = Sys_LoadLibrary(fullname, funcs);
|
||||
|
@ -1308,6 +1309,20 @@ void CLHL_LoadClientGame(void)
|
|||
CLHL_cgamefuncs.HUD_Init();
|
||||
if (CLHL_cgamefuncs.HUD_VidInit)
|
||||
CLHL_cgamefuncs.HUD_VidInit();
|
||||
{
|
||||
struct hlkbutton_s
|
||||
{
|
||||
int down[2]; // key nums holding it down
|
||||
int state; // low bit is down state
|
||||
} *but;
|
||||
struct hlkbutton_s *(QDECL *pKB_Find) (const char *foo) = (void*)Sys_GetAddressForName(clg, "KB_Find");
|
||||
if (pKB_Find)
|
||||
{
|
||||
but = pKB_Find("in_mlook");
|
||||
if (but)
|
||||
but->state |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CLHL_BuildUserInput(int msecs, usercmd_t *cmd)
|
||||
|
@ -1329,7 +1344,7 @@ int CLHL_BuildUserInput(int msecs, usercmd_t *cmd)
|
|||
cmd->upmove = hlcmd.upmove;
|
||||
cmd->weapon = hlcmd.weaponselect;
|
||||
cmd->impulse = hlcmd.impulse;
|
||||
cmd->buttons = hlcmd.buttons;
|
||||
cmd->buttons = hlcmd.buttons & 0xff; //FIXME: quake's protocols are more limited than this
|
||||
cmd->lightlevel = hlcmd.lightlevel;
|
||||
return true;
|
||||
#else
|
||||
|
@ -1365,7 +1380,7 @@ int CLHL_DrawHud(void)
|
|||
|
||||
CLHL_cgamefuncs.HUD_UpdateClientData(&state, cl.time);
|
||||
|
||||
ret = CLHL_cgamefuncs.HUD_Redraw(cl.time, cl.intermission);
|
||||
ret = CLHL_cgamefuncs.HUD_Redraw(cl.time, cl.intermissionmode != IM_NONE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1383,7 +1398,7 @@ int CLHL_AnimateViewEntity(entity_t *ent)
|
|||
return true;
|
||||
}
|
||||
|
||||
explosion_t *CL_AllocExplosion (void);
|
||||
explosion_t *CL_AllocExplosion (vec3_t org);
|
||||
|
||||
int CLHL_ParseGamePacket(void)
|
||||
{
|
||||
|
@ -1445,19 +1460,18 @@ int CLHL_ParseGamePacket(void)
|
|||
if (!(flags & 8))
|
||||
P_RunParticleEffectType(startp, NULL, 1, pt_explosion);
|
||||
if (!(flags & 4))
|
||||
S_StartSound(0, 0, S_PrecacheSound("explosion"), startp, 1, 1, 0, 0);
|
||||
S_StartSound(0, 0, S_PrecacheSound("explosion"), startp, 1, 1, 0, 0, 0);
|
||||
if (!(flags & 2))
|
||||
CL_NewDlight(0, startp, 200, 1, 2.0,2.0,2.0);
|
||||
|
||||
ef = CL_AllocExplosion();
|
||||
VectorCopy(startp, ef->origin);
|
||||
ef = CL_AllocExplosion(startp);
|
||||
ef->start = cl.time;
|
||||
ef->model = cl.model_precache[midx];
|
||||
ef->framerate = mrate;
|
||||
ef->firstframe = 0;
|
||||
ef->numframes = ef->model->numframes;
|
||||
if (!(flags & 1))
|
||||
ef->flags = Q2RF_ADDITIVE;
|
||||
ef->flags = RF_ADDITIVE;
|
||||
else
|
||||
ef->flags = 0;
|
||||
break;
|
||||
|
@ -1503,8 +1517,7 @@ int CLHL_ParseGamePacket(void)
|
|||
MSG_ReadByte();
|
||||
lifetime = MSG_ReadByte();
|
||||
|
||||
ef = CL_AllocExplosion();
|
||||
VectorCopy(startp, ef->origin);
|
||||
ef = CL_AllocExplosion(startp);
|
||||
ef->start = cl.time;
|
||||
ef->angles[1] = ang;
|
||||
ef->model = cl.model_precache[midx];
|
||||
|
@ -1554,7 +1567,7 @@ int CLHL_ParseGamePacket(void)
|
|||
break;
|
||||
case svc_intermission:
|
||||
//nothing.
|
||||
cl.intermission = true;
|
||||
cl.intermissionmode = IM_NQSCORES;
|
||||
break;
|
||||
case svc_cdtrack:
|
||||
{
|
||||
|
@ -1572,7 +1585,7 @@ int CLHL_ParseGamePacket(void)
|
|||
break;
|
||||
case 37: //svc_roomtype
|
||||
tempi = MSG_ReadShort();
|
||||
S_SetUnderWater(tempi==14||tempi==15||tempi==16);
|
||||
// S_SetUnderWater(tempi==14||tempi==15||tempi==16);
|
||||
break;
|
||||
default:
|
||||
Con_Printf("Unrecognised gamecode packet %i (%s)\n", subcode, usermsgs[subcode].name);
|
||||
|
|
|
@ -303,6 +303,9 @@ typedef struct dlight_s
|
|||
unsigned int flags;
|
||||
char cubemapname[64];
|
||||
|
||||
int coronaocclusionquery;
|
||||
unsigned int coronaocclusionresult;
|
||||
|
||||
//the following are used for rendering (client code should clear on create)
|
||||
qboolean rebuildcache;
|
||||
struct shadowmesh_s *worldshadowmesh;
|
||||
|
@ -975,7 +978,6 @@ void CL_FreeDlights(void);
|
|||
dlight_t *CL_AllocDlight (int key);
|
||||
dlight_t *CL_AllocSlight (void); //allocates a static light
|
||||
dlight_t *CL_NewDlight (int key, const vec3_t origin, float radius, float time, float r, float g, float b);
|
||||
dlight_t *CL_NewDlightRGB (int key, const vec3_t origin, float radius, float time, float r, float g, float b);
|
||||
dlight_t *CL_NewDlightCube (int key, const vec3_t origin, vec3_t angles, float radius, float time, vec3_t colours);
|
||||
void CL_DecayLights (void);
|
||||
|
||||
|
|
|
@ -971,6 +971,17 @@ void VARGS Con_SafeTPrintf (translation_t text, ...)
|
|||
Con_Printf ("%s", msg);
|
||||
}
|
||||
|
||||
static void Con_DPrintFromThread (void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
if (!developer.value)
|
||||
Con_Log(data);
|
||||
else
|
||||
{
|
||||
Sys_Printf ("%s", data); // also echo to debugging console
|
||||
Con_PrintCon(&con_main, data, con_main.parseflags);
|
||||
}
|
||||
BZ_Free(data);
|
||||
}
|
||||
/*
|
||||
================
|
||||
Con_DPrintf
|
||||
|
@ -999,6 +1010,13 @@ void VARGS Con_DPrintf (const char *fmt, ...)
|
|||
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
if (!Sys_IsMainThread())
|
||||
{
|
||||
if (developer.ival)
|
||||
COM_AddWork(0, Con_DPrintFromThread, NULL, Z_StrDup(msg), 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!developer.value)
|
||||
Con_Log(msg);
|
||||
else
|
||||
|
|
|
@ -28,7 +28,9 @@ char *r_defaultimageextensions =
|
|||
#if defined(AVAIL_JPEGLIB) || defined(FTE_TARGET_WEB)
|
||||
" jpg" //q3 uses some jpegs, for some reason
|
||||
#endif
|
||||
#ifndef NOLEGACY
|
||||
" pcx" //pcxes are the original gamedata of q2. So we don't want them to override pngs.
|
||||
#endif
|
||||
;
|
||||
static void QDECL R_ImageExtensions_Callback(struct cvar_s *var, char *oldvalue);
|
||||
cvar_t r_imageexensions = CVARCD("r_imageexensions", NULL, R_ImageExtensions_Callback, "The list of image file extensions which fte should attempt to load.");
|
||||
|
@ -2783,7 +2785,9 @@ static struct
|
|||
{3, "textures/%s/%s%s", 1}, /*fuhquake compatibility*/
|
||||
{3, "%s/%s%s", 1}, /*fuhquake compatibility*/
|
||||
{2, "textures/%s%s", 1}, /*directly named texture with textures/ prefix*/
|
||||
#ifndef NOLEGACY
|
||||
{2, "override/%s%s", 1} /*tenebrae compatibility*/
|
||||
#endif
|
||||
};
|
||||
|
||||
static void Image_MipMap8888 (qbyte *in, int inwidth, int inheight, qbyte *out, int outwidth, int outheight)
|
||||
|
@ -3676,6 +3680,54 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
freedata = true;
|
||||
break;
|
||||
|
||||
case TF_MIP4_8PAL24:
|
||||
//8bit opaque data
|
||||
{
|
||||
unsigned int pixels =
|
||||
(imgwidth>>0) * (imgheight>>0) +
|
||||
(imgwidth>>1) * (imgheight>>1) +
|
||||
(imgwidth>>2) * (imgheight>>2) +
|
||||
(imgwidth>>3) * (imgheight>>3);
|
||||
palettedata = (qbyte*)rawdata + pixels;
|
||||
Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags);
|
||||
flags |= IF_NOPICMIP;
|
||||
if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight && sh_config.texfmt[PTI_RGBX8])
|
||||
{
|
||||
unsigned int pixels =
|
||||
(imgwidth>>0) * (imgheight>>0) +
|
||||
(imgwidth>>1) * (imgheight>>1) +
|
||||
(imgwidth>>2) * (imgheight>>2) +
|
||||
(imgwidth>>3) * (imgheight>>3);
|
||||
|
||||
mips->encoding = PTI_RGBX8;
|
||||
rgbadata = BZ_Malloc(pixels*4);
|
||||
for (i = 0; i < pixels; i++)
|
||||
{
|
||||
qbyte *p = ((qbyte*)palettedata) + ((qbyte*)rawdata)[i]*3;
|
||||
//FIXME: endian
|
||||
rgbadata[i] = 0xff000000 | (p[0]<<0) | (p[1]<<8) | (p[2]<<16);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
mips->mip[i].width = imgwidth>>i;
|
||||
mips->mip[i].height = imgheight>>i;
|
||||
mips->mip[i].datasize = mips->mip[i].width * mips->mip[i].height * 4;
|
||||
mips->mip[i].needfree = false;
|
||||
}
|
||||
mips->mipcount = i;
|
||||
mips->mip[0].data = rgbadata;
|
||||
mips->mip[1].data = (qbyte*)mips->mip[0].data + mips->mip[0].datasize;
|
||||
mips->mip[2].data = (qbyte*)mips->mip[1].data + mips->mip[1].datasize;
|
||||
mips->mip[3].data = (qbyte*)mips->mip[2].data + mips->mip[2].datasize;
|
||||
|
||||
mips->extrafree = rgbadata;
|
||||
if (freedata)
|
||||
BZ_Free(rawdata);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//fall through
|
||||
case TF_8PAL24:
|
||||
if (!palettedata)
|
||||
{
|
||||
|
@ -4458,6 +4510,8 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
|
|||
case TF_BGRA32:
|
||||
b *= 4;
|
||||
break;
|
||||
case TF_MIP4_8PAL24:
|
||||
pb = 3*256;
|
||||
case TF_MIP4_LUM8:
|
||||
case TF_MIP4_SOLID8:
|
||||
b = (fallbackwidth>>0)*(fallbackheight>>0) +
|
||||
|
@ -4508,9 +4562,9 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
|
|||
else
|
||||
#endif
|
||||
if (lowpri)
|
||||
COM_AddWork(5, Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
|
||||
COM_AddWork(1, Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
|
||||
else
|
||||
COM_AddWork(2+(seq++%3), Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
|
||||
COM_AddWork(1, Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
|
@ -4711,6 +4765,7 @@ void Image_List_f(void)
|
|||
//may not create any images yet.
|
||||
void Image_Init(void)
|
||||
{
|
||||
wadmutex = Sys_CreateMutex();
|
||||
memset(imagetablebuckets, 0, sizeof(imagetablebuckets));
|
||||
Hash_InitTable(&imagetable, sizeof(imagetablebuckets)/sizeof(imagetablebuckets[0]), imagetablebuckets);
|
||||
|
||||
|
@ -4736,6 +4791,10 @@ void Image_Shutdown(void)
|
|||
}
|
||||
if (i)
|
||||
Con_DPrintf("Destroyed %i/%i images\n", j, i);
|
||||
|
||||
if (wadmutex)
|
||||
Sys_DestroyMutex(wadmutex);
|
||||
wadmutex = NULL;
|
||||
}
|
||||
|
||||
//load the named file, without failing.
|
||||
|
|
|
@ -433,6 +433,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
|
|||
int mfwt;
|
||||
qboolean strafe_x, strafe_y;
|
||||
int wpnum;
|
||||
extern qboolean runningindepphys;
|
||||
|
||||
//small performance boost
|
||||
if (mouse->type == M_INVALID)
|
||||
|
@ -570,7 +571,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
|
|||
#ifdef PEXT_CSQC
|
||||
if (mouse->type == M_TOUCH)
|
||||
{
|
||||
if (CSQC_MousePosition(mouse->oldpos[0], mouse->oldpos[1], mouse->qdeviceid))
|
||||
if (!runningindepphys && CSQC_MousePosition(mouse->oldpos[0], mouse->oldpos[1], mouse->qdeviceid))
|
||||
{
|
||||
mx = 0;
|
||||
my = 0;
|
||||
|
@ -579,7 +580,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
|
|||
else
|
||||
{
|
||||
if (mx || my)
|
||||
if (CSQC_MouseMove(mx, my, mouse->qdeviceid))
|
||||
if (!runningindepphys && CSQC_MouseMove(mx, my, mouse->qdeviceid))
|
||||
{
|
||||
mx = 0;
|
||||
my = 0;
|
||||
|
|
|
@ -1651,7 +1651,7 @@ cin_t *Media_WinAvi_TryLoad(char *name)
|
|||
return NULL;
|
||||
|
||||
|
||||
FS_FLocateFile(name, FSLFRT_DEPTH_OSONLY, &loc);
|
||||
FS_FLocateFile(name, FSLF_IFFOUND, &loc);
|
||||
|
||||
if (!loc.offset && *loc.rawname && !qAVIFileOpenA(&pavi, loc.rawname, OF_READ, NULL))//!AVIStreamOpenFromFile(&pavi, name, streamtypeVIDEO, 0, OF_READ, NULL))
|
||||
{
|
||||
|
@ -4424,6 +4424,15 @@ static void S_MP3_Purge(sfx_t *sfx)
|
|||
sfx->loadstate = SLS_NOTLOADED;
|
||||
}
|
||||
|
||||
float S_MP3_Query(sfx_t *sfx, sfxcache_t *buf)
|
||||
{
|
||||
//we don't know unless we decode it all
|
||||
if (buf)
|
||||
{
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*must be thread safe*/
|
||||
sfxcache_t *S_MP3_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start, int length)
|
||||
{
|
||||
|
@ -4552,6 +4561,7 @@ qboolean S_LoadMP3Sound (sfx_t *s, qbyte *data, int datalen, int sndspeed)
|
|||
s->decoder.ended = S_MP3_Purge;
|
||||
s->decoder.purge = S_MP3_Purge;
|
||||
s->decoder.decodedata = S_MP3_Locate;
|
||||
s->decoder.querydata = S_MP3_Query;
|
||||
|
||||
dec->dstdata = NULL;
|
||||
dec->dstcount = 0;
|
||||
|
|
|
@ -190,6 +190,7 @@ typedef enum uploadfmt
|
|||
TF_LUM8, /*8bit greyscale image*/
|
||||
TF_MIP4_LUM8, /*8bit 4-mip greyscale image*/
|
||||
TF_MIP4_SOLID8, /*8bit 4-mip image*/
|
||||
TF_MIP4_8PAL24, /*8bit 4-mip image*/
|
||||
TF_SOLID8, /*8bit quake-palette image*/
|
||||
TF_TRANS8, /*8bit quake-palette image, index 255=transparent*/
|
||||
TF_TRANS8_FULLBRIGHT, /*fullbright 8 - fullbright texels have alpha 255, everything else 0*/
|
||||
|
@ -427,7 +428,7 @@ typedef struct rendererinfo_s {
|
|||
void (*BE_SubmitBatch)(struct batch_s *batch);
|
||||
struct batch_s *(*BE_GetTempBatch)(void);
|
||||
//Asks the backend to invoke DrawMeshChain for each surface, and to upload lightmaps as required
|
||||
void (*BE_DrawWorld) (qboolean drawworld, qbyte *vis);
|
||||
void (*BE_DrawWorld) (struct batch_s **worldbatches, qbyte *vis);
|
||||
//called at init, force the display to the right defaults etc
|
||||
void (*BE_Init)(void);
|
||||
//Generates an optimised VBO, one for each texture on the map
|
||||
|
|
|
@ -227,6 +227,7 @@ typedef struct part_type_s {
|
|||
float orgadd, randomorgadd; //spawn the particle this far along its velocity direction
|
||||
float spawnvel, spawnvelvert; //spawn the particle with a velocity based upon its spawn type (generally so it flies outwards)
|
||||
vec3_t orgbias; //static 3d world-coord bias
|
||||
float viewspacefrac;
|
||||
|
||||
float s1, t1, s2, t2; //texture coords
|
||||
float texsstride; //addition for s for each random slot.
|
||||
|
@ -316,6 +317,7 @@ typedef struct part_type_s {
|
|||
#define PT_TROVERWATER 0x0200 // don't spawn if underwater
|
||||
#define PT_TRUNDERWATER 0x0400 // don't spawn if overwater
|
||||
#define PT_NODLSHADOW 0x0800 // dlights from this effect don't cast shadows.
|
||||
unsigned int fluidmask;
|
||||
|
||||
unsigned int state;
|
||||
#define PS_INRUNLIST 0x1 // particle type is currently in execution list
|
||||
|
@ -953,6 +955,7 @@ static void P_ResetToDefaults(part_type_t *ptype)
|
|||
ptype->inwater = P_INVALID;
|
||||
ptype->cliptype = P_INVALID;
|
||||
ptype->emit = P_INVALID;
|
||||
ptype->fluidmask = FTECONTENTS_FLUID;
|
||||
ptype->alpha = 1;
|
||||
ptype->alphachange = 1;
|
||||
ptype->clipbounce = 0.8;
|
||||
|
@ -1243,7 +1246,7 @@ void P_ParticleEffect_f(void)
|
|||
ptype->alpha = atof(value);
|
||||
else if (!strcmp(var, "alphachange"))
|
||||
{
|
||||
Con_DPrintf("alphachange is deprecated, use alphadelta\n");
|
||||
Con_DPrintf("%s.%s: alphachange is deprecated, use alphadelta\n", ptype->config, ptype->name);
|
||||
ptype->alphachange = atof(value);
|
||||
}
|
||||
else if (!strcmp(var, "alphadelta"))
|
||||
|
@ -1268,7 +1271,7 @@ void P_ParticleEffect_f(void)
|
|||
}
|
||||
else if (!strcmp(var, "diesubrand"))
|
||||
{
|
||||
Con_DPrintf("diesubrand is deprecated, use die with two arguments\n");
|
||||
Con_DPrintf("%s.%s: diesubrand is deprecated, use die with two arguments\n", ptype->config, ptype->name);
|
||||
ptype->randdie = atof(value);
|
||||
}
|
||||
|
||||
|
@ -1339,6 +1342,49 @@ void P_ParticleEffect_f(void)
|
|||
ptype = &part_type[pnum];
|
||||
ptype->inwater = assoc;
|
||||
}
|
||||
else if (!strcmp(var, "underwater"))
|
||||
{
|
||||
ptype->flags |= PT_TRUNDERWATER;
|
||||
|
||||
parsefluid:
|
||||
if ((ptype->flags & (PT_TRUNDERWATER|PT_TROVERWATER)) == (PT_TRUNDERWATER|PT_TROVERWATER))
|
||||
{
|
||||
ptype->flags &= ~PT_TRUNDERWATER;
|
||||
Con_Printf("%s.%s: both over and under water\n", ptype->config, ptype->name);
|
||||
}
|
||||
if (Cmd_Argc() == 1)
|
||||
ptype->fluidmask = FTECONTENTS_FLUID;
|
||||
else
|
||||
{
|
||||
int i = Cmd_Argc();
|
||||
ptype->fluidmask = 0;
|
||||
while (i --> 1)
|
||||
{
|
||||
char *value = Cmd_Argv(i);
|
||||
if (!strcmp(value, "water"))
|
||||
ptype->fluidmask |= FTECONTENTS_WATER;
|
||||
else if (!strcmp(value, "slime"))
|
||||
ptype->fluidmask |= FTECONTENTS_SLIME;
|
||||
else if (!strcmp(value, "lava"))
|
||||
ptype->fluidmask |= FTECONTENTS_LAVA;
|
||||
else if (!strcmp(value, "sky"))
|
||||
ptype->fluidmask |= FTECONTENTS_SKY;
|
||||
else if (!strcmp(value, "fluid"))
|
||||
ptype->fluidmask |= FTECONTENTS_FLUID;
|
||||
else if (!strcmp(value, "solid"))
|
||||
ptype->fluidmask |= FTECONTENTS_SOLID;
|
||||
else if (!strcmp(value, "playerclip"))
|
||||
ptype->fluidmask |= FTECONTENTS_PLAYERCLIP;
|
||||
else
|
||||
Con_Printf("%s.%s: unknown contents: %s\n", ptype->config, ptype->name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(var, "notunderwater"))
|
||||
{
|
||||
ptype->flags |= PT_TROVERWATER;
|
||||
goto parsefluid;
|
||||
}
|
||||
else if (!strcmp(var, "model"))
|
||||
{
|
||||
partmodels_t *mod;
|
||||
|
@ -1623,7 +1669,7 @@ void P_ParticleEffect_f(void)
|
|||
}
|
||||
else if (!strcmp(var, "isbeam"))
|
||||
{
|
||||
Con_DPrintf("isbeam is deprecated, use type beam\n");
|
||||
Con_DPrintf("%s.%s: isbeam is deprecated, use type beam\n", ptype->config, ptype->name);
|
||||
ptype->looks.type = PT_BEAM;
|
||||
}
|
||||
else if (!strcmp(var, "spawntime"))
|
||||
|
@ -1662,22 +1708,22 @@ void P_ParticleEffect_f(void)
|
|||
// old names
|
||||
else if (!strcmp(var, "areaspread"))
|
||||
{
|
||||
Con_DPrintf("areaspread is deprecated, use spawnorg\n");
|
||||
Con_DPrintf("%s.%s: areaspread is deprecated, use spawnorg\n", ptype->config, ptype->name);
|
||||
ptype->areaspread = atof(value);
|
||||
}
|
||||
else if (!strcmp(var, "areaspreadvert"))
|
||||
{
|
||||
Con_DPrintf("areaspreadvert is deprecated, use spawnorg\n");
|
||||
Con_DPrintf("%s.%s: areaspreadvert is deprecated, use spawnorg\n", ptype->config, ptype->name);
|
||||
ptype->areaspreadvert = atof(value);
|
||||
}
|
||||
else if (!strcmp(var, "offsetspread"))
|
||||
{
|
||||
Con_DPrintf("offsetspread is deprecated, use spawnvel\n");
|
||||
Con_DPrintf("%s.%s: offsetspread is deprecated, use spawnvel\n", ptype->config, ptype->name);
|
||||
ptype->spawnvel = atof(value);
|
||||
}
|
||||
else if (!strcmp(var, "offsetspreadvert"))
|
||||
{
|
||||
Con_DPrintf("offsetspreadvert is deprecated, use spawnvel\n");
|
||||
Con_DPrintf("%s.%s: offsetspreadvert is deprecated, use spawnvel\n", ptype->config, ptype->name);
|
||||
ptype->spawnvelvert = atof(value);
|
||||
}
|
||||
|
||||
|
@ -1713,7 +1759,7 @@ void P_ParticleEffect_f(void)
|
|||
ptype->rampmode = RAMP_NONE;
|
||||
else if (!strcmp(value, "absolute"))
|
||||
{
|
||||
Con_DPrintf("'rampmode absolute' is deprecated, use 'rampmode nearest'\n");
|
||||
Con_DPrintf("%s.%s: 'rampmode absolute' is deprecated, use 'rampmode nearest'\n", ptype->config, ptype->name);
|
||||
ptype->rampmode = RAMP_NEAREST;
|
||||
}
|
||||
else if (!strcmp(value, "nearest"))
|
||||
|
@ -1805,6 +1851,8 @@ void P_ParticleEffect_f(void)
|
|||
|
||||
ptype->rampindexes++;
|
||||
}
|
||||
else if (!strcmp(var, "viewspace"))
|
||||
ptype->viewspacefrac = (Cmd_Argc()>1)?atof(value):1;
|
||||
else if (!strcmp(var, "perframe"))
|
||||
ptype->flags |= PT_INVFRAMETIME;
|
||||
else if (!strcmp(var, "averageout"))
|
||||
|
@ -1819,7 +1867,7 @@ void P_ParticleEffect_f(void)
|
|||
else if (!strcmp(var, "lightradius"))
|
||||
{ //float version
|
||||
ptype->dl_radius[0] = ptype->dl_radius[1] = atof(value);
|
||||
if (Cmd_Argc()>3)
|
||||
if (Cmd_Argc()>2)
|
||||
ptype->dl_radius[1] = atof(Cmd_Argv(2));
|
||||
ptype->dl_radius[1] -= ptype->dl_radius[0];
|
||||
}
|
||||
|
@ -1862,7 +1910,7 @@ void P_ParticleEffect_f(void)
|
|||
ptype->stain_rgb[2] = atof(Cmd_Argv(4));
|
||||
}
|
||||
else
|
||||
Con_DPrintf("%s is not a recognised particle type field (in %s)\n", var, ptype->name);
|
||||
Con_DPrintf("%s.%s: %s is not a recognised particle type field\n", ptype->config, ptype->name, var);
|
||||
}
|
||||
ptype->looks.invscalefactor = 1-ptype->looks.scalefactor;
|
||||
ptype->loaded = part_parseweak?1:2;
|
||||
|
@ -1883,12 +1931,12 @@ void P_ParticleEffect_f(void)
|
|||
if (ptype->scale)
|
||||
{
|
||||
ptype->looks.type = PT_SPARKFAN;
|
||||
Con_DPrintf("effect %s lacks a texture. assuming type sparkfan.\n", ptype->name);
|
||||
Con_DPrintf("%s.%s: effect lacks a texture. assuming type sparkfan.\n", ptype->config, ptype->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptype->looks.type = PT_SPARK;
|
||||
Con_DPrintf("effect %s lacks a texture. assuming type spark.\n", ptype->name);
|
||||
Con_DPrintf("%s.%s: effect lacks a texture. assuming type spark.\n", ptype->config, ptype->name);
|
||||
}
|
||||
}
|
||||
else if (ptype->looks.type == PT_SPARK)
|
||||
|
@ -1924,11 +1972,11 @@ void P_ParticleEffect_f(void)
|
|||
if (ptype->rampmode && !ptype->ramp)
|
||||
{
|
||||
ptype->rampmode = RAMP_NONE;
|
||||
Con_Printf("Particle type %s has a ramp mode but no ramp\n", ptype->name);
|
||||
Con_Printf("%s.%s: Particle has a ramp mode but no ramp\n", ptype->config, ptype->name);
|
||||
}
|
||||
else if (ptype->ramp && !ptype->rampmode)
|
||||
{
|
||||
Con_Printf("Particle type %s has a ramp but no ramp mode\n", ptype->name);
|
||||
Con_Printf("%s.%s: Particle has a ramp but no ramp mode\n", ptype->config, ptype->name);
|
||||
}
|
||||
|
||||
P_LoadTexture(ptype, true);
|
||||
|
@ -2108,6 +2156,9 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen)
|
|||
if (ptype->areaspread || ptype->areaspreadvert)
|
||||
Q_strncatz(outstr, va("spawnorg %g %g\n", ptype->areaspread, ptype->areaspreadvert), outstrlen);
|
||||
|
||||
if (ptype->viewspacefrac)
|
||||
Q_strncatz(outstr, ((ptype->viewspacefrac==1)?"viewspace\n":va("viewspace %g\n", ptype->viewspacefrac)), outstrlen);
|
||||
|
||||
if (ptype->veladd || ptype->randomveladd)
|
||||
{
|
||||
if (ptype->randomveladd)
|
||||
|
@ -3920,9 +3971,9 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
|
|||
int cont;
|
||||
cont = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, org);
|
||||
|
||||
if ((ptype->flags & PT_TROVERWATER) && (cont & FTECONTENTS_FLUID))
|
||||
if ((ptype->flags & PT_TROVERWATER) && (cont & ptype->fluidmask))
|
||||
goto skip;
|
||||
if ((ptype->flags & PT_TRUNDERWATER) && !(cont & FTECONTENTS_FLUID))
|
||||
if ((ptype->flags & PT_TRUNDERWATER) && !(cont & ptype->fluidmask))
|
||||
goto skip;
|
||||
}
|
||||
|
||||
|
@ -4724,9 +4775,9 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype
|
|||
int cont;
|
||||
cont = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, startpos);
|
||||
|
||||
if ((ptype->flags & PT_TROVERWATER) && (cont & FTECONTENTS_FLUID))
|
||||
if ((ptype->flags & PT_TROVERWATER) && (cont & ptype->fluidmask))
|
||||
return;
|
||||
if ((ptype->flags & PT_TRUNDERWATER) && !(cont & FTECONTENTS_FLUID))
|
||||
if ((ptype->flags & PT_TRUNDERWATER) && !(cont & ptype->fluidmask))
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5853,6 +5904,8 @@ static void R_AddTexturedParticle(scenetris_t *t, particle_t *p, plooks_t *type)
|
|||
|
||||
static void PScript_DrawParticleTypes (void)
|
||||
{
|
||||
float viewtranslation[16];
|
||||
static float lastviewmatrix[16];
|
||||
// void (*sparklineparticles)(int count, particle_t **plist, plooks_t *type)=R_AddLineSparkParticle;
|
||||
void (*sparkfanparticles)(int count, particle_t **plist, plooks_t *type)=GL_DrawTrifanParticle;
|
||||
void (*sparktexturedparticles)(int count, particle_t **plist, plooks_t *type)=GL_DrawTexturedSparkParticle;
|
||||
|
@ -5924,6 +5977,14 @@ static void PScript_DrawParticleTypes (void)
|
|||
|
||||
kill_list = kill_first = NULL;
|
||||
|
||||
|
||||
{
|
||||
float tmp[16];
|
||||
Matrix4_Invert(r_refdef.m_view, tmp);
|
||||
Matrix4_Multiply(tmp, lastviewmatrix, viewtranslation);
|
||||
memcpy(lastviewmatrix, r_refdef.m_view, sizeof(tmp));
|
||||
}
|
||||
|
||||
for (type = part_run_list, lastvalidtype = NULL; type != NULL; type = type->nexttorun)
|
||||
{
|
||||
if (type->clippeddecals)
|
||||
|
@ -6254,6 +6315,15 @@ static void PScript_DrawParticleTypes (void)
|
|||
p->vel[2] -= grav;
|
||||
}
|
||||
|
||||
if (type->viewspacefrac)
|
||||
{
|
||||
vec3_t tmp;
|
||||
Matrix4x4_CM_Transform3(viewtranslation, p->org, tmp);
|
||||
VectorInterpolate(p->org, type->viewspacefrac, tmp, p->org);
|
||||
Matrix4x4_CM_Transform3x3(viewtranslation, p->vel, tmp);
|
||||
VectorInterpolate(p->vel, type->viewspacefrac, tmp, p->vel);
|
||||
}
|
||||
|
||||
p->angle += p->rotationspeed*pframetime;
|
||||
|
||||
switch (type->rampmode)
|
||||
|
|
|
@ -540,16 +540,26 @@ void QCBUILTIN PF_soundlength (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
|||
const char *sample = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
|
||||
sfx_t *sfx = S_PrecacheSound(sample);
|
||||
if (sfx && sfx->loadstate == SLS_LOADING)
|
||||
COM_WorkerPartialSync(sfx, &sfx->loadstate, SLS_LOADING);
|
||||
if (!sfx || sfx->loadstate != SLS_LOADED)
|
||||
G_FLOAT(OFS_RETURN) = 0;
|
||||
else
|
||||
{
|
||||
sfxcache_t cachebuf, *cache;
|
||||
if (sfx->decoder.decodedata)
|
||||
if (sfx->decoder.querydata)
|
||||
{
|
||||
G_FLOAT(OFS_RETURN) = sfx->decoder.querydata(sfx, NULL);
|
||||
return;
|
||||
}
|
||||
else if (sfx->decoder.decodedata)
|
||||
cache = sfx->decoder.decodedata(sfx, &cachebuf, 0x7ffffffe, 0);
|
||||
else
|
||||
cache = sfx->decoder.buf;
|
||||
G_FLOAT(OFS_RETURN) = (cache->soundoffset+cache->length) / (float)snd_speed;
|
||||
if (!cache)
|
||||
G_FLOAT(OFS_RETURN) = 0;
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = (cache->soundoffset+cache->length) / (float)snd_speed;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1864,6 +1864,9 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars
|
|||
csqc_worldchanged = false;
|
||||
Surf_NewMap();
|
||||
CL_UpdateWindowTitle();
|
||||
|
||||
World_RBE_Shutdown(&csqc_world);
|
||||
World_RBE_Start(&csqc_world);
|
||||
}
|
||||
|
||||
if (cl.worldmodel)
|
||||
|
|
|
@ -2327,6 +2327,15 @@ pbool PDECL Menu_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc)
|
|||
return crc == 10020;
|
||||
}
|
||||
|
||||
static int QDECL MP_PRFileSize (const char *path)
|
||||
{
|
||||
flocation_t loc;
|
||||
if (FS_FLocateFile(path, FSLF_IFFOUND|FSLF_SECUREONLY, &loc))
|
||||
return loc.len;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
double menutime;
|
||||
qboolean MP_Init (void)
|
||||
{
|
||||
|
@ -2350,7 +2359,7 @@ qboolean MP_Init (void)
|
|||
|
||||
menuprogparms.progsversion = PROGSTRUCT_VERSION;
|
||||
menuprogparms.ReadFile = COM_LoadStackFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
|
||||
menuprogparms.FileSize = COM_FileSize;//int (*FileSize) (char *fname); //-1 if file does not exist
|
||||
menuprogparms.FileSize = MP_PRFileSize;//int (*FileSize) (char *fname); //-1 if file does not exist
|
||||
menuprogparms.WriteFile = QC_WriteFile;//bool (*WriteFile) (char *name, void *data, int len);
|
||||
menuprogparms.Printf = (void *)Con_Printf;//Con_Printf;//void (*printf) (char *, ...);
|
||||
menuprogparms.Sys_Error = Sys_Error;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -302,7 +302,7 @@ void Surf_RenderAmbientLightmaps (struct msurface_s *fa, int ambient);
|
|||
int Surf_LightmapShift (struct model_s *model);
|
||||
#define LMBLOCK_SIZE_MAX 2048 //single axis
|
||||
typedef struct glRect_s {
|
||||
unsigned short l,t,w,h;
|
||||
unsigned short l,t,r,b;
|
||||
} glRect_t;
|
||||
typedef unsigned char stmap;
|
||||
struct mesh_s;
|
||||
|
@ -488,7 +488,7 @@ double Media_TweekCaptureFrameTime(double oldtime, double time);
|
|||
void MYgluPerspective(double fovx, double fovy, double zNear, double zFar);
|
||||
|
||||
void R_PushDlights (void);
|
||||
qbyte *R_MarkLeaves_Q1 (void);
|
||||
qbyte *R_MarkLeaves_Q1 (qboolean getvisonly);
|
||||
qbyte *R_CalcVis_Q1 (void);
|
||||
qbyte *R_MarkLeaves_Q2 (void);
|
||||
qbyte *R_MarkLeaves_Q3 (void);
|
||||
|
|
|
@ -112,7 +112,7 @@ cvar_t r_skin_overlays = SCVARF ("r_skin_overlays", "1",
|
|||
cvar_t r_globalskin_first = CVARFD ("r_globalskin_first", "100", CVAR_RENDERERLATCH, "Specifies the first .skin value that is a global skin. Entities within this range will use the shader/image called 'gfx/skinSKIN.lmp' instead of their regular skin. See also: r_globalskin_count.");
|
||||
cvar_t r_globalskin_count = CVARFD ("r_globalskin_count", "10", CVAR_RENDERERLATCH, "Specifies how many globalskins there are.");
|
||||
cvar_t r_coronas = CVARFD ("r_coronas", "0", CVAR_ARCHIVE, "Draw coronas on realtime lights. Overrides glquake-esque flashblends.");
|
||||
cvar_t r_coronas_occlusion = CVARFD ("r_coronas_occlusion", "1", CVAR_ARCHIVE, "Specifies that coronas should be occluded more carefully.\n0: BSP occlusion only.\n1: non-bsp occlusion also");
|
||||
cvar_t r_coronas_occlusion = CVARFD ("r_coronas_occlusion", "", CVAR_ARCHIVE, "Specifies that coronas should be occluded more carefully.\n0: No occlusion, at all.\n1: BSP occlusion only (simple tracelines).\n2: non-bsp occlusion also (complex tracelines).\n3: Depthbuffer reads (forces synchronisation).\n4: occlusion queries.");
|
||||
cvar_t r_flashblend = SCVARF ("gl_flashblend", "0",
|
||||
CVAR_ARCHIVE);
|
||||
cvar_t r_flashblendscale = SCVARF ("gl_flashblendscale", "0.35",
|
||||
|
@ -398,7 +398,7 @@ cvar_t r_fastturbcolour = CVARFD ("r_fastturbcolour", "0.1 0.2 0.3", CVAR_A
|
|||
cvar_t r_waterstyle = CVARFD ("r_waterstyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes how water, and teleporters are drawn. Possible values are:\n0: fastturb-style block colour.\n1: regular q1-style water.\n2: refraction(ripply and transparent)\n3: refraction with reflection at an angle\n4: ripplemapped without reflections (requires particle effects)\n5: ripples+reflections");
|
||||
cvar_t r_slimestyle = CVARFD ("r_slimestyle", "", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only slime. If empty, defers to r_waterstyle.");
|
||||
cvar_t r_lavastyle = CVARFD ("r_lavastyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only lava. If empty, defers to r_waterstyle.");
|
||||
cvar_t r_telestyle = CVARFD ("r_telestyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only lava. If empty, defers to r_waterstyle.");
|
||||
cvar_t r_telestyle = CVARFD ("r_telestyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only teleporters. If empty, defers to r_waterstyle.");
|
||||
|
||||
cvar_t r_vertexdlights = CVARD ("r_vertexdlights", "0", "Determine model lighting with respect to nearby dlights. Poor-man's rtlights.");
|
||||
|
||||
|
@ -2209,7 +2209,7 @@ qbyte *R_CalcVis_Q1 (void)
|
|||
}
|
||||
#endif
|
||||
|
||||
qbyte *R_MarkLeaves_Q1 (void)
|
||||
qbyte *R_MarkLeaves_Q1 (qboolean getvisonly)
|
||||
{
|
||||
static qbyte *cvis[R_MAX_RECURSE];
|
||||
qbyte *vis;
|
||||
|
@ -2271,7 +2271,9 @@ qbyte *R_MarkLeaves_Q1 (void)
|
|||
|
||||
r_visframecount++;
|
||||
|
||||
if (r_viewleaf && r_viewleaf->contents == Q1CONTENTS_SOLID)
|
||||
if (getvisonly)
|
||||
return vis;
|
||||
else if (r_viewleaf && r_viewleaf->contents == Q1CONTENTS_SOLID)
|
||||
{
|
||||
//to improve spectating, when the camera is in a wall, we ignore any sky leafs.
|
||||
//this prevents seeing the upwards-facing sky surfaces within the sky volumes.
|
||||
|
|
|
@ -2165,7 +2165,7 @@ void Sbar_DrawScoreboard (void)
|
|||
|
||||
for (pnum = 0; pnum < cl.splitclients; pnum++)
|
||||
{
|
||||
if (cl.spectator)
|
||||
if (cl.spectator && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV))
|
||||
{
|
||||
int t = cl.playerview[pnum].cam_spec_track;
|
||||
if (t < 0 || !CAM_ISLOCKED(&cl.playerview[pnum]))
|
||||
|
|
256
engine/client/snd_xaudio.c
Normal file
256
engine/client/snd_xaudio.c
Normal file
|
@ -0,0 +1,256 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
//frankly, xaudio2 gives nothing over directsound, unless we're getting it to do all the mixing instead. which gets really messy and far too involved.
|
||||
//I suppose it has a use with WINRT... although that doesn't make it useful.
|
||||
//we're lazy and don't do any special threading, this makes it inferior to the directsound implementation - potentially, the callback feature could allow for slightly lower latencies.
|
||||
|
||||
#if defined(AVAIL_XAUDIO2) && !defined(SERVERONLY)
|
||||
#include "winquake.h"
|
||||
#include <xaudio2.h>
|
||||
|
||||
#define SDRVNAME "XAudio2"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IXAudio2VoiceCallback cb; //must be first. yay for fake single inheritance.
|
||||
|
||||
IXAudio2 *ixa;
|
||||
IXAudio2MasteringVoice *master;
|
||||
IXAudio2SourceVoice *source;
|
||||
|
||||
//contiguous block of memory, because its easier.
|
||||
qbyte *bufferstart;
|
||||
unsigned int subbuffersize; //in samplepairs
|
||||
unsigned int buffercount;
|
||||
unsigned int bufferidx;
|
||||
unsigned int bufferavail;
|
||||
} xaud_t;
|
||||
|
||||
static void *XAUDIO_Lock(soundcardinfo_t *sc, unsigned int *startoffset)
|
||||
{
|
||||
qbyte *ret;
|
||||
xaud_t *xa = sc->handle;
|
||||
ret = xa->bufferstart;
|
||||
|
||||
// *startoffset = 0;
|
||||
// ret += xa->subbuffersize * xa->bufferidx;
|
||||
|
||||
return ret;
|
||||
}
|
||||
static void XAUDIO_Unlock(soundcardinfo_t *sc, void *buffer)
|
||||
{
|
||||
}
|
||||
static unsigned int XAUDIO_GetDMAPos(soundcardinfo_t *sc)
|
||||
{
|
||||
xaud_t *xa = sc->handle;
|
||||
unsigned int s = (xa->bufferidx+xa->bufferavail) * xa->subbuffersize * sc->sn.numchannels;
|
||||
return s;
|
||||
}
|
||||
static void XAUDIO_Submit(soundcardinfo_t *sc, int start, int end)
|
||||
{
|
||||
xaud_t *xa = sc->handle;
|
||||
XAUDIO2_BUFFER buf;
|
||||
|
||||
//determine total buffer size
|
||||
int buffersize = sc->sn.samples*sc->sn.samplebits/8;
|
||||
|
||||
//determine time offsets in bytes
|
||||
start *= sc->sn.numchannels*sc->sn.samplebits/8;
|
||||
end *= sc->sn.numchannels*sc->sn.samplebits/8;
|
||||
|
||||
while (start < end)
|
||||
{
|
||||
if (!xa->bufferavail)
|
||||
break; //o.O that's not meant to happen
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.AudioBytes = end - start;
|
||||
if (buf.AudioBytes > xa->subbuffersize * sc->sn.numchannels*sc->sn.samplebits/8)
|
||||
{
|
||||
if (buf.AudioBytes < xa->subbuffersize * sc->sn.numchannels*sc->sn.samplebits/8)
|
||||
{ //dma code should ensure that only multiples of 'samplequeue' are processed.
|
||||
Con_Printf("XAudio2 underrun\n");
|
||||
break;
|
||||
}
|
||||
buf.AudioBytes = xa->subbuffersize * sc->sn.numchannels*sc->sn.samplebits/8;
|
||||
}
|
||||
buf.pAudioData = xa->bufferstart + (start%buffersize);
|
||||
if ((qbyte*)buf.pAudioData + buf.AudioBytes > xa->bufferstart + buffersize)
|
||||
{ //this shouldn't ever happen either
|
||||
Con_Printf("XAudio2 overrun\n");
|
||||
break;
|
||||
}
|
||||
IXAudio2SourceVoice_SubmitSourceBuffer(xa->source, &buf, NULL);
|
||||
xa->bufferidx += 1;
|
||||
xa->bufferavail -= 1;
|
||||
start += buf.AudioBytes;
|
||||
}
|
||||
}
|
||||
|
||||
static void XAUDIO_Shutdown(soundcardinfo_t *sc)
|
||||
{
|
||||
xaud_t *xa = sc->handle;
|
||||
//releases are allowed to block, supposedly.
|
||||
IXAudio2SourceVoice_DestroyVoice(xa->source);
|
||||
IXAudio2MasteringVoice_DestroyVoice(xa->master);
|
||||
IXAudio2_Release(xa->ixa);
|
||||
BZ_Free(xa->bufferstart);
|
||||
Z_Free(xa);
|
||||
sc->handle = NULL;
|
||||
}
|
||||
|
||||
void WINAPI XAUDIO_CB_OnVoiceProcessingPassStart (IXAudio2VoiceCallback *ths, UINT32 BytesRequired) {}
|
||||
void WINAPI XAUDIO_CB_OnVoiceProcessingPassEnd (IXAudio2VoiceCallback *ths) {}
|
||||
void WINAPI XAUDIO_CB_OnStreamEnd (IXAudio2VoiceCallback *ths) {}
|
||||
void WINAPI XAUDIO_CB_OnBufferStart (IXAudio2VoiceCallback *ths, void* pBufferContext) {}
|
||||
void WINAPI XAUDIO_CB_OnBufferEnd (IXAudio2VoiceCallback *ths, void* pBufferContext) {xaud_t *xa = (xaud_t*)ths; S_LockMixer(); xa->bufferavail+=1; S_UnlockMixer();}
|
||||
void WINAPI XAUDIO_CB_OnLoopEnd (IXAudio2VoiceCallback *ths, void* pBufferContext) {}
|
||||
void WINAPI XAUDIO_CB_OnVoiceError (IXAudio2VoiceCallback *ths, void* pBufferContext, HRESULT Error) {}
|
||||
static IXAudio2VoiceCallbackVtbl cbvtbl =
|
||||
{
|
||||
XAUDIO_CB_OnVoiceProcessingPassStart,
|
||||
XAUDIO_CB_OnVoiceProcessingPassEnd,
|
||||
XAUDIO_CB_OnStreamEnd,
|
||||
XAUDIO_CB_OnBufferStart,
|
||||
XAUDIO_CB_OnBufferEnd,
|
||||
XAUDIO_CB_OnLoopEnd,
|
||||
XAUDIO_CB_OnVoiceError
|
||||
};
|
||||
|
||||
static qboolean QDECL XAUDIO_InitCard(soundcardinfo_t *sc, const char *cardname)
|
||||
{
|
||||
#ifdef WINRT
|
||||
char *dev = NULL;
|
||||
#else
|
||||
int dev = 0;
|
||||
#endif
|
||||
xaud_t *xa = Z_Malloc(sizeof(*xa));
|
||||
WAVEFORMATEX wfmt;
|
||||
|
||||
xa->cb.lpVtbl = &cbvtbl;
|
||||
|
||||
sc->sn.numchannels = 2;
|
||||
|
||||
wfmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfmt.nChannels = sc->sn.numchannels;
|
||||
wfmt.nSamplesPerSec = sc->sn.speed;
|
||||
wfmt.wBitsPerSample = sc->sn.samplebits;
|
||||
wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
|
||||
wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
|
||||
wfmt.cbSize = 0;
|
||||
|
||||
sc->inactive_sound = true;
|
||||
xa->buffercount = xa->bufferavail = 3; //submit this many straight up
|
||||
xa->subbuffersize = 256; //number of sampleblocks per submission
|
||||
sc->samplequeue = -1; //-1 means we're streaming, XAUDIO_GetDMAPos returns exactly as much as we want to paint to.
|
||||
|
||||
sc->sn.samples = xa->buffercount * xa->subbuffersize * sc->sn.numchannels;
|
||||
|
||||
xa->bufferstart = BZ_Malloc(sc->sn.samples * (sc->sn.samplebits/8));
|
||||
|
||||
if (xa->bufferstart)
|
||||
{
|
||||
if (SUCCEEDED(XAudio2Create(&xa->ixa, 0, XAUDIO2_DEFAULT_PROCESSOR)))
|
||||
{
|
||||
#ifdef WINRT
|
||||
if (SUCCEEDED(IXAudio2_CreateMasteringVoice(xa->ixa, &xa->master, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, dev, NULL, AudioCategory_GameEffects)))
|
||||
#else
|
||||
if (cardname && *cardname)
|
||||
{
|
||||
UINT32 devs = 0;
|
||||
XAUDIO2_DEVICE_DETAILS details;
|
||||
char id[MAX_QPATH];
|
||||
if (FAILED(IXAudio2_GetDeviceCount(xa->ixa, &devs)))
|
||||
devs = 0;
|
||||
|
||||
for (dev = 0; dev < devs; dev++)
|
||||
{
|
||||
if (SUCCEEDED(IXAudio2_GetDeviceDetails(xa->ixa, dev, &details)))
|
||||
{
|
||||
narrowen(id, sizeof(id), details.DeviceID);
|
||||
|
||||
if (!strcmp(id, cardname))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dev == devs)
|
||||
dev = ~0; //something invalid.
|
||||
}
|
||||
|
||||
/*
|
||||
//FIXME: correct the details to match the hardware
|
||||
*/
|
||||
|
||||
|
||||
if (dev != ~0 && SUCCEEDED(IXAudio2_CreateMasteringVoice(xa->ixa, &xa->master, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, dev, NULL)))
|
||||
#endif
|
||||
{
|
||||
//egads
|
||||
XAUDIO2_VOICE_SENDS vs;
|
||||
XAUDIO2_SEND_DESCRIPTOR sd[1];
|
||||
vs.SendCount = 1;
|
||||
vs.pSends = sd;
|
||||
sd[0].Flags = 0;
|
||||
sd[0].pOutputVoice = (IXAudio2Voice*)xa->master;
|
||||
|
||||
if (SUCCEEDED(IXAudio2_CreateSourceVoice(xa->ixa, &xa->source, &wfmt, 0, XAUDIO2_DEFAULT_FREQ_RATIO, &xa->cb, &vs, NULL)))
|
||||
{
|
||||
sc->handle = xa;
|
||||
sc->GetDMAPos = XAUDIO_GetDMAPos;
|
||||
sc->Lock = XAUDIO_Lock;
|
||||
sc->Unlock = XAUDIO_Unlock;
|
||||
sc->Submit = XAUDIO_Submit;
|
||||
sc->Shutdown = XAUDIO_Shutdown;
|
||||
|
||||
IXAudio2SourceVoice_Start(xa->source, 0, XAUDIO2_COMMIT_NOW);
|
||||
return true;
|
||||
}
|
||||
IXAudio2MasteringVoice_DestroyVoice(xa->master);
|
||||
}
|
||||
IXAudio2_Release(xa->ixa);
|
||||
}
|
||||
BZ_Free(xa->bufferstart);
|
||||
}
|
||||
Z_Free(xa);
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean QDECL XAUDIO_Enumerate(void (QDECL *callback) (const char *drivername, const char *devicecode, const char *readablename))
|
||||
{
|
||||
IXAudio2 *ixa;
|
||||
#ifndef WINRT
|
||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
//winrt provides no enumeration mechanism.
|
||||
if (SUCCEEDED(XAudio2Create(&ixa, 0, XAUDIO2_DEFAULT_PROCESSOR)))
|
||||
{
|
||||
UINT32 devs = 0, i;
|
||||
XAUDIO2_DEVICE_DETAILS details;
|
||||
char id[MAX_QPATH], name[MAX_QPATH];
|
||||
if (FAILED(IXAudio2_GetDeviceCount(ixa, &devs)))
|
||||
devs = 0;
|
||||
|
||||
strcpy(name, "XA2:");
|
||||
|
||||
for (i = 0; i < devs; i++)
|
||||
{
|
||||
if (SUCCEEDED(IXAudio2_GetDeviceDetails(ixa, i, &details)))
|
||||
{
|
||||
narrowen(id, sizeof(id), details.DeviceID);
|
||||
narrowen(name+4, sizeof(name)-4, details.DisplayName);
|
||||
|
||||
callback(SDRVNAME, id, name);
|
||||
}
|
||||
}
|
||||
IXAudio2_Release(ixa);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
sounddriver_t XAUDIO2_Output =
|
||||
{
|
||||
SDRVNAME,
|
||||
XAUDIO_InitCard,
|
||||
XAUDIO_Enumerate
|
||||
};
|
||||
#endif
|
|
@ -25,12 +25,6 @@ static void Headless_IMG_UpdateFiltering (image_t *imagelist, int filtermip[3],
|
|||
}
|
||||
static qboolean Headless_IMG_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < mips->mipcount; i++)
|
||||
if (mips->mip[i].needfree)
|
||||
Z_Free(mips->mip[i].data);
|
||||
if (mips->extrafree)
|
||||
Z_Free(mips->extrafree);
|
||||
return true;
|
||||
}
|
||||
static void Headless_IMG_DestroyTexture (texid_t tex)
|
||||
|
@ -141,6 +135,8 @@ static qboolean Headless_VID_Init (rendererstate_t *info, unsigned char *pale
|
|||
Shell_NotifyIconA(NIM_ADD, &data);
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&sh_config, 0, sizeof(sh_config));
|
||||
return true;
|
||||
}
|
||||
static void Headless_VID_DeInit (void)
|
||||
|
@ -196,7 +192,7 @@ static struct batch_s *Headless_BE_GetTempBatch (void)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
static void Headless_BE_DrawWorld (qboolean drawworld, qbyte *vis)
|
||||
static void Headless_BE_DrawWorld (struct batch_s **worldbatches, qbyte *vis)
|
||||
{
|
||||
}
|
||||
static void Headless_BE_Init (void)
|
||||
|
|
|
@ -244,6 +244,14 @@ void SwapPic (qpic_t *pic)
|
|||
//FIXME: convert to linked list. is hunk possible?
|
||||
//hash tables?
|
||||
#define TEXWAD_MAXIMAGES 16384
|
||||
|
||||
typedef struct wadfile_s
|
||||
{
|
||||
vfsfile_t *file;
|
||||
struct wadfile_s *next;
|
||||
char name[1];
|
||||
} wadfile_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[16];
|
||||
|
@ -253,18 +261,15 @@ typedef struct
|
|||
} texwadlump_t;
|
||||
int numwadtextures;
|
||||
static texwadlump_t texwadlump[TEXWAD_MAXIMAGES];
|
||||
|
||||
typedef struct wadfile_s {
|
||||
vfsfile_t *file;
|
||||
struct wadfile_s *next;
|
||||
char name[1];
|
||||
} wadfile_t;
|
||||
void *wadmutex;
|
||||
|
||||
wadfile_t *openwadfiles;
|
||||
|
||||
void Wads_Flush (void)
|
||||
{
|
||||
wadfile_t *wf;
|
||||
if (wadmutex)
|
||||
Sys_LockMutex(wadmutex);
|
||||
while(openwadfiles)
|
||||
{
|
||||
VFS_CLOSE(openwadfiles->file);
|
||||
|
@ -275,6 +280,8 @@ void Wads_Flush (void)
|
|||
}
|
||||
|
||||
numwadtextures=0;
|
||||
if (wadmutex)
|
||||
Sys_UnlockMutex(wadmutex);
|
||||
}
|
||||
/*
|
||||
====================
|
||||
|
@ -411,12 +418,23 @@ qbyte *W_ConvertWAD3Texture(miptex_t *tex, size_t lumpsize, int *width, int *hei
|
|||
tex->offsets[1] == tex->offsets[0] + (tex->width)*(tex->height) &&
|
||||
tex->offsets[2] == tex->offsets[1] + (tex->width>>1)*(tex->height>>1) &&
|
||||
tex->offsets[3] == tex->offsets[2] + (tex->width>>2)*(tex->height>>2) &&
|
||||
lumpsize == tex->offsets[3] + (tex->width>>3)*(tex->height>>3) + 2 + 768)
|
||||
((lumpsize+3)&~3) >= ((tex->offsets[3] + (tex->width>>3)*(tex->height>>3) + 2 + 768+3)&~3))
|
||||
pal = (qbyte *)tex + tex->offsets[3] + (tex->width>>3)*(tex->height>>3) + 2;
|
||||
else
|
||||
pal = host_basepal;
|
||||
|
||||
for (d = 0;d < tex->width * tex->height;d++)
|
||||
if (tex->offsets[0] + tex->width * tex->height > lumpsize)
|
||||
{ //fucked texture.
|
||||
for (d = 0;d < tex->width * tex->height;d++)
|
||||
{
|
||||
out[0] = 0;
|
||||
out[1] = 255;
|
||||
out[2] = 0;
|
||||
out[3] = 255;
|
||||
out += 4;
|
||||
}
|
||||
}
|
||||
else for (d = 0;d < tex->width * tex->height;d++)
|
||||
{
|
||||
p = *in++;
|
||||
if (alpha==1 && p == 255) //only allow alpha on '{' textures
|
||||
|
@ -473,30 +491,34 @@ qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalp
|
|||
|
||||
texname[16] = 0;
|
||||
W_CleanupName (name, texname);
|
||||
Sys_LockMutex(wadmutex);
|
||||
for (i = 0;i < numwadtextures;i++)
|
||||
{
|
||||
if (!strcmp(texname, texwadlump[i].name)) // found it
|
||||
{
|
||||
file = texwadlump[i].file;
|
||||
if (!VFS_SEEK(file, texwadlump[i].position))
|
||||
{Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
|
||||
|
||||
tex = BZ_Malloc(texwadlump[i].size); //temp buffer for disk info (was hunk_tempalloc, but that wiped loading maps and the like
|
||||
if (!tex)
|
||||
return NULL;
|
||||
if (VFS_READ(file, tex, texwadlump[i].size) < texwadlump[i].size)
|
||||
{Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
|
||||
if (VFS_SEEK(file, texwadlump[i].position))
|
||||
{
|
||||
tex = BZ_Malloc(texwadlump[i].size); //temp buffer for disk info (was hunk_tempalloc, but that wiped loading maps and the like
|
||||
if (tex && VFS_READ(file, tex, texwadlump[i].size) == texwadlump[i].size)
|
||||
{
|
||||
Sys_UnlockMutex(wadmutex);
|
||||
tex->width = LittleLong(tex->width);
|
||||
tex->height = LittleLong(tex->height);
|
||||
for (j = 0;j < MIPLEVELS;j++)
|
||||
tex->offsets[j] = LittleLong(tex->offsets[j]);
|
||||
|
||||
tex->width = LittleLong(tex->width);
|
||||
tex->height = LittleLong(tex->height);
|
||||
for (j = 0;j < MIPLEVELS;j++)
|
||||
tex->offsets[j] = LittleLong(tex->offsets[j]);
|
||||
|
||||
data = W_ConvertWAD3Texture(tex, texwadlump[i].size, width, height, usesalpha);
|
||||
BZ_Free(tex);
|
||||
return data;
|
||||
data = W_ConvertWAD3Texture(tex, texwadlump[i].size, width, height, usesalpha);
|
||||
BZ_Free(tex);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
Con_Printf("W_GetTexture: corrupt WAD3 file\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Sys_UnlockMutex(wadmutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -509,27 +531,30 @@ miptex_t *W_GetMipTex(const char *name)
|
|||
|
||||
texname[16] = 0;
|
||||
W_CleanupName (name, texname);
|
||||
Sys_LockMutex(wadmutex);
|
||||
for (i = 0;i < numwadtextures;i++)
|
||||
{
|
||||
if (!strcmp(texname, texwadlump[i].name)) // found it
|
||||
{
|
||||
file = texwadlump[i].file;
|
||||
if (!VFS_SEEK(file, texwadlump[i].position))
|
||||
{Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
|
||||
|
||||
tex = BZ_Malloc(texwadlump[i].size); //temp buffer for disk info (was hunk_tempalloc, but that wiped loading maps and the like
|
||||
if (!tex)
|
||||
return NULL;
|
||||
if (VFS_READ(file, tex, texwadlump[i].size) < texwadlump[i].size)
|
||||
{Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
|
||||
|
||||
tex->width = LittleLong(tex->width);
|
||||
tex->height = LittleLong(tex->height);
|
||||
for (j = 0;j < MIPLEVELS;j++)
|
||||
tex->offsets[j] = LittleLong(tex->offsets[j]);
|
||||
return tex;
|
||||
if (VFS_SEEK(file, texwadlump[i].position))
|
||||
{
|
||||
tex = BZ_Malloc(texwadlump[i].size); //temp buffer for disk info (was hunk_tempalloc, but that wiped loading maps and the like
|
||||
if (tex && VFS_READ(file, tex, texwadlump[i].size) == texwadlump[i].size)
|
||||
{
|
||||
Sys_UnlockMutex(wadmutex);
|
||||
tex->width = LittleLong(tex->width);
|
||||
tex->height = LittleLong(tex->height);
|
||||
for (j = 0;j < MIPLEVELS;j++)
|
||||
tex->offsets[j] = LittleLong(tex->offsets[j]);
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
Con_Printf("W_GetTexture: corrupt WAD3 file\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Sys_UnlockMutex(wadmutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -689,12 +714,14 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
|
|||
key[3] = ' ';
|
||||
Q_strncpyz(key+4, token, sizeof(key)-4);
|
||||
Cbuf_AddText(key, RESTRICT_INSECURE);
|
||||
Cbuf_AddText("\n", RESTRICT_INSECURE);
|
||||
}
|
||||
else if (!strcmp("waterfog", key)) //q1 extension. FIXME: should be made temporary.
|
||||
{
|
||||
memcpy(key, "waterfog ", 9);
|
||||
Q_strncpyz(key+9, token, sizeof(key)-9);
|
||||
Cbuf_AddText(key, RESTRICT_INSECURE);
|
||||
Cbuf_AddText("\n", RESTRICT_INSECURE);
|
||||
}
|
||||
else if (!strncmp("cvar_", key, 5)) //override cvars so mappers don't end up hacking cvars and fucking over configs (at least in other engines).
|
||||
{
|
||||
|
|
|
@ -93,6 +93,7 @@ void *W_GetLumpName (char *name);
|
|||
void *W_SafeGetLumpName (const char *name);
|
||||
void *W_GetLumpNum (int num);
|
||||
void Wads_Flush (void);
|
||||
extern void *wadmutex;
|
||||
|
||||
void SwapPic (qpic_t *pic);
|
||||
|
||||
|
|
|
@ -3546,7 +3546,7 @@ qbool TP_CheckSoundTrigger (char *str)
|
|||
COM_DefaultExtension (soundname, ".wav", sizeof(soundname));
|
||||
|
||||
// make sure we have it on disk (FIXME)
|
||||
if (!FS_FLocateFile (va("sound/%s", soundname), FSLFRT_IFFOUND, NULL))
|
||||
if (!FS_FLocateFile (va("sound/%s", soundname), FSLF_IFFOUND, NULL))
|
||||
return false;
|
||||
|
||||
// now play the sound
|
||||
|
|
|
@ -179,7 +179,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#undef AVAIL_JPEGLIB
|
||||
#undef AVAIL_XZDEC
|
||||
|
||||
#if defined(_WIN32) && !defined(FTE_SDL) !defined(MULTITHREAD) //always thread on win32 non-minimal builds
|
||||
#if defined(_WIN32) && !defined(FTE_SDL) && !defined(MULTITHREAD) //always thread on win32 non-minimal builds
|
||||
#define MULTITHREAD
|
||||
#endif
|
||||
#elif defined(MINIMAL)
|
||||
|
|
|
@ -616,7 +616,7 @@ void Cmd_Exec_f (void)
|
|||
else
|
||||
Q_strncpyz(name, Cmd_Argv(1), sizeof(name));
|
||||
|
||||
if (!FS_FLocateFile(name, FSLFRT_IFFOUND, &loc) && !FS_FLocateFile(va("%s.cfg", name), FSLFRT_IFFOUND, &loc))
|
||||
if (!FS_FLocateFile(name, FSLF_IFFOUND, &loc) && !FS_FLocateFile(va("%s.cfg", name), FSLF_IFFOUND, &loc))
|
||||
{
|
||||
Con_TPrintf ("couldn't exec %s\n", name);
|
||||
return;
|
||||
|
|
|
@ -984,7 +984,7 @@ void R_LightArrays(const entity_t *entity, vecV_t *coords, avec4_t *colours, int
|
|||
}
|
||||
}
|
||||
|
||||
if (r_vertexdlights.ival && r_dynamic.ival)
|
||||
if (r_vertexdlights.ival && r_dynamic.ival > 0)
|
||||
{
|
||||
unsigned int lno, v;
|
||||
vec3_t dir, rel;
|
||||
|
@ -2787,13 +2787,11 @@ void Mod_LoadAliasShaders(model_t *mod)
|
|||
|
||||
//Q1 model loading
|
||||
#if 1
|
||||
static galiasinfo_t *galias;
|
||||
static dmdl_t *pq1inmodel;
|
||||
#define NUMVERTEXNORMALS 162
|
||||
extern float r_avertexnormals[NUMVERTEXNORMALS][3];
|
||||
// mdltype 0 = q1, 1 = qtest, 2 = rapo/h2
|
||||
|
||||
static void Alias_LoadPose(vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t *tvec, dtrivertx_t *pinframe, int *seamremaps, int mdltype)
|
||||
static void Q1MDL_LoadPose(galiasinfo_t *galias, dmdl_t *pq1inmodel, vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t *tvec, dtrivertx_t *pinframe, int *seamremaps, int mdltype)
|
||||
{
|
||||
int j;
|
||||
#ifdef HEXEN2
|
||||
|
@ -2830,7 +2828,7 @@ static void Alias_LoadPose(vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t
|
|||
}
|
||||
}
|
||||
}
|
||||
static void Alias_LoadPose16(vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t *tvec, dtrivertx_t *pinframe, int *seamremaps, int mdltype)
|
||||
static void Q1MDL_LoadPose16(galiasinfo_t *galias, dmdl_t *pq1inmodel, vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t *tvec, dtrivertx_t *pinframe, int *seamremaps, int mdltype)
|
||||
{
|
||||
//quakeforge's MD16 format has regular 8bit stuff, trailed by an extra low-order set of the verts providing the extra 8bits of precision.
|
||||
//its worth noting that the model could be rendered using the high-order parts only, if your software renderer only supports that or whatever.
|
||||
|
@ -2855,7 +2853,7 @@ static void Alias_LoadPose16(vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_
|
|||
}
|
||||
}
|
||||
}
|
||||
static void *Alias_LoadFrameGroup (model_t *loadmodel, daliasframetype_t *pframetype, int *seamremaps, int mdltype)
|
||||
static void *Q1MDL_LoadFrameGroup (galiasinfo_t *galias, dmdl_t *pq1inmodel, model_t *loadmodel, daliasframetype_t *pframetype, int *seamremaps, int mdltype)
|
||||
{
|
||||
galiaspose_t *pose;
|
||||
galiasanimation_t *frame = galias->ofsanimations;
|
||||
|
@ -2910,12 +2908,12 @@ static void *Alias_LoadFrameGroup (model_t *loadmodel, daliasframetype_t *pframe
|
|||
|
||||
if (mdltype & 16)
|
||||
{
|
||||
Alias_LoadPose16(verts, normals, svec, tvec, pinframe, seamremaps, mdltype);
|
||||
Q1MDL_LoadPose16(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype);
|
||||
pframetype = (daliasframetype_t *)&pinframe[pq1inmodel->numverts*2];
|
||||
}
|
||||
else
|
||||
{
|
||||
Alias_LoadPose(verts, normals, svec, tvec, pinframe, seamremaps, mdltype);
|
||||
Q1MDL_LoadPose(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype);
|
||||
pframetype = (daliasframetype_t *)&pinframe[pq1inmodel->numverts];
|
||||
}
|
||||
|
||||
|
@ -2972,12 +2970,12 @@ static void *Alias_LoadFrameGroup (model_t *loadmodel, daliasframetype_t *pframe
|
|||
|
||||
if (mdltype & 16)
|
||||
{
|
||||
Alias_LoadPose16(verts, normals, svec, tvec, pinframe, seamremaps, mdltype);
|
||||
Q1MDL_LoadPose16(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype);
|
||||
pinframe += pq1inmodel->numverts*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Alias_LoadPose(verts, normals, svec, tvec, pinframe, seamremaps, mdltype);
|
||||
Q1MDL_LoadPose(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype);
|
||||
pinframe += pq1inmodel->numverts;
|
||||
}
|
||||
|
||||
|
@ -3007,7 +3005,7 @@ static void *Alias_LoadFrameGroup (model_t *loadmodel, daliasframetype_t *pframe
|
|||
|
||||
//greatly reduced version of Q1_LoadSkins
|
||||
//just skips over the data
|
||||
static void *Q1_LoadSkins_SV (daliasskintype_t *pskintype, unsigned int skintranstype)
|
||||
static void *Q1MDL_LoadSkins_SV (galiasinfo_t *galias, dmdl_t *pq1inmodel, daliasskintype_t *pskintype, unsigned int skintranstype)
|
||||
{
|
||||
int i;
|
||||
int s;
|
||||
|
@ -3038,7 +3036,7 @@ static void *Q1_LoadSkins_SV (daliasskintype_t *pskintype, unsigned int skintran
|
|||
}
|
||||
|
||||
#ifndef SERVERONLY
|
||||
static void *Q1_LoadSkins_GL (model_t *loadmodel, daliasskintype_t *pskintype, uploadfmt_t skintranstype)
|
||||
static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model_t *loadmodel, daliasskintype_t *pskintype, uploadfmt_t skintranstype)
|
||||
{
|
||||
skinframe_t *frames;
|
||||
char skinname[MAX_QPATH];
|
||||
|
@ -3362,8 +3360,8 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize)
|
|||
dh2triangle_t *pinh2triangles;
|
||||
qboolean rapo = false;
|
||||
#endif
|
||||
|
||||
pq1inmodel = (dmdl_t *)buffer;
|
||||
galiasinfo_t *galias;
|
||||
dmdl_t *pq1inmodel = (dmdl_t *)buffer;
|
||||
|
||||
hdrsize = sizeof(dmdl_t) - sizeof(int);
|
||||
|
||||
|
@ -3450,11 +3448,11 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize)
|
|||
{
|
||||
default:
|
||||
#ifndef SERVERONLY
|
||||
pinstverts = (dstvert_t *)Q1_LoadSkins_GL(mod, skinstart, skintranstype);
|
||||
pinstverts = (dstvert_t *)Q1MDL_LoadSkins_GL(galias, pq1inmodel, mod, skinstart, skintranstype);
|
||||
break;
|
||||
#endif
|
||||
case QR_NONE:
|
||||
pinstverts = (dstvert_t *)Q1_LoadSkins_SV(skinstart, skintranstype);
|
||||
pinstverts = (dstvert_t *)Q1MDL_LoadSkins_SV(galias, pq1inmodel, skinstart, skintranstype);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3535,7 +3533,7 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize)
|
|||
#endif
|
||||
end = &pinh2triangles[pq1inmodel->numtris];
|
||||
|
||||
if (Alias_LoadFrameGroup(mod, (daliasframetype_t *)end, seamremap, 2) == NULL)
|
||||
if (Q1MDL_LoadFrameGroup(galias, pq1inmodel, mod, (daliasframetype_t *)end, seamremap, 2) == NULL)
|
||||
{
|
||||
BZ_Free(seamremap);
|
||||
ZG_FreeGroup(&mod->memgroup);
|
||||
|
@ -3612,7 +3610,7 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize)
|
|||
end = &pinq1triangles[pq1inmodel->numtris];
|
||||
|
||||
//frames
|
||||
if (Alias_LoadFrameGroup(mod, (daliasframetype_t *)end, seamremap, (sixteenbit?16:0) | (qtest?1:0)) == NULL)
|
||||
if (Q1MDL_LoadFrameGroup(galias, pq1inmodel, mod, (daliasframetype_t *)end, seamremap, (sixteenbit?16:0) | (qtest?1:0)) == NULL)
|
||||
{
|
||||
BZ_Free(seamremap);
|
||||
ZG_FreeGroup(&mod->memgroup);
|
||||
|
@ -3706,7 +3704,7 @@ typedef struct
|
|||
#define Q2NUMVERTEXNORMALS 162
|
||||
extern vec3_t bytedirs[Q2NUMVERTEXNORMALS];
|
||||
|
||||
static void Q2_LoadSkins(model_t *mod, md2_t *pq2inmodel, char *skins)
|
||||
static void Q2MD2_LoadSkins(galiasinfo_t *galias, model_t *mod, md2_t *pq2inmodel, char *skins)
|
||||
{
|
||||
#ifndef SERVERONLY
|
||||
int i;
|
||||
|
@ -3777,6 +3775,7 @@ qboolean QDECL Mod_LoadQ2Model (model_t *mod, void *buffer, size_t fsize)
|
|||
int numverts;
|
||||
|
||||
int size;
|
||||
galiasinfo_t *galias;
|
||||
|
||||
mod->engineflags |= MDLF_NEEDOVERBRIGHT;
|
||||
|
||||
|
@ -3820,7 +3819,7 @@ qboolean QDECL Mod_LoadQ2Model (model_t *mod, void *buffer, size_t fsize)
|
|||
galias->nextsurf = 0;
|
||||
|
||||
//skins
|
||||
Q2_LoadSkins(mod, pq2inmodel, ((char *)pq2inmodel+LittleLong(pq2inmodel->ofs_skins)));
|
||||
Q2MD2_LoadSkins(galias, mod, pq2inmodel, ((char *)pq2inmodel+LittleLong(pq2inmodel->ofs_skins)));
|
||||
|
||||
//trianglelists;
|
||||
pintri = (dmd2triangle_t *)((char *)pq2inmodel + LittleLong(pq2inmodel->ofs_tris));
|
||||
|
@ -4604,6 +4603,7 @@ qboolean QDECL Mod_LoadQ3Model(model_t *mod, void *buffer, size_t fsize)
|
|||
|
||||
md3Header_t *header;
|
||||
md3Surface_t *surf;
|
||||
galiasinfo_t *galias;
|
||||
|
||||
header = buffer;
|
||||
|
||||
|
|
|
@ -4724,11 +4724,24 @@ void COM_ErrorMe_f(void)
|
|||
|
||||
|
||||
#ifdef LOADERTHREAD
|
||||
#define WORKERTHREADS (1+1+4)
|
||||
#define WG_MAIN 0
|
||||
#define WG_LOADER 1
|
||||
#define WG_COUNT 2 //main and loaders
|
||||
#define WORKERTHREADS 16 //max
|
||||
/*multithreading worker thread stuff*/
|
||||
static void *com_workercondition[WORKERTHREADS];
|
||||
static qboolean com_workerdone[WORKERTHREADS];
|
||||
static void *com_workerthread[WORKERTHREADS];
|
||||
static int com_liveworkers[WG_COUNT];
|
||||
static void *com_workercondition[WG_COUNT];
|
||||
static volatile int com_workeracksequence;
|
||||
static struct com_worker_s
|
||||
{
|
||||
void *thread;
|
||||
volatile enum {
|
||||
WR_NONE,
|
||||
WR_DIE,
|
||||
WR_ACK //updates ackseq to com_workeracksequence and sends a signal to WG_MAIN
|
||||
} request;
|
||||
volatile int ackseq;
|
||||
} com_worker[WORKERTHREADS];
|
||||
static unsigned int mainthreadid;
|
||||
qboolean com_workererror;
|
||||
static struct com_work_s
|
||||
|
@ -4739,77 +4752,12 @@ static struct com_work_s
|
|||
void *data;
|
||||
size_t a;
|
||||
size_t b;
|
||||
} *com_work_head[WORKERTHREADS], *com_work_tail[WORKERTHREADS];
|
||||
static void Sys_ErrorThread(void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
Sys_Error(data);
|
||||
}
|
||||
void COM_WorkerAbort(char *message)
|
||||
{
|
||||
int us;
|
||||
struct com_work_s work;
|
||||
if (Sys_IsMainThread())
|
||||
return;
|
||||
com_workererror = true;
|
||||
|
||||
if (!com_workercondition[0])
|
||||
return; //Sys_IsMainThread was probably called too early...
|
||||
|
||||
memset(&work, 0, sizeof(work));
|
||||
work.func = Sys_ErrorThread;
|
||||
work.ctx = NULL;
|
||||
work.data = message;
|
||||
work.a = 0;
|
||||
work.b = 0;
|
||||
|
||||
Sys_LockConditional(com_workercondition[0]);
|
||||
if (com_work_tail[0])
|
||||
{
|
||||
com_work_tail[0]->next = &work;
|
||||
com_work_tail[0] = &work;
|
||||
}
|
||||
else
|
||||
com_work_head[0] = com_work_tail[0] = &work;
|
||||
Sys_ConditionSignal(com_workercondition[0]);
|
||||
Sys_UnlockConditional(com_workercondition[0]);
|
||||
|
||||
//find out which worker we are
|
||||
for (us = WORKERTHREADS-1; us > 0; us--)
|
||||
if (Sys_IsThread(com_workerthread[us]))
|
||||
break;
|
||||
if (us)
|
||||
{
|
||||
//and post any pending work we have back over to the main thread, because we're going down as soon as we can.
|
||||
while(!com_workerdone[us])
|
||||
{
|
||||
struct com_work_s *w;
|
||||
Sys_LockConditional(com_workercondition[us]);
|
||||
w = com_work_head[us];
|
||||
if (w)
|
||||
com_work_head[us] = w->next;
|
||||
if (!com_work_head[us])
|
||||
com_work_head[us] = com_work_tail[us] = NULL;
|
||||
Sys_UnlockConditional(com_workercondition[us]);
|
||||
if (w)
|
||||
{
|
||||
COM_AddWork(0, w->func, w->ctx, w->data, w->a, w->b);
|
||||
Z_Free(w);
|
||||
}
|
||||
else
|
||||
Sys_ConditionSignal(com_workercondition[0]);
|
||||
|
||||
Sys_Sleep(0.1);
|
||||
}
|
||||
com_workerdone[0] = true;
|
||||
Sys_ConditionSignal(com_workercondition[0]);
|
||||
}
|
||||
Sys_ThreadAbort();
|
||||
}
|
||||
} *com_work_head[WG_COUNT], *com_work_tail[WG_COUNT];
|
||||
//return if there's *any* loading that needs to be done anywhere.
|
||||
qboolean COM_HasWork(void)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < WORKERTHREADS-1; i++)
|
||||
for (i = 0; i < WG_COUNT; i++)
|
||||
{
|
||||
if (com_work_head[i])
|
||||
return true;
|
||||
|
@ -4817,12 +4765,15 @@ qboolean COM_HasWork(void)
|
|||
return false;
|
||||
}
|
||||
//thread==0 is main thread, thread==1 is a worker thread
|
||||
void COM_AddWork(int thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b)
|
||||
void COM_AddWork(int tg, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
struct com_work_s *work;
|
||||
|
||||
if (tg >= WG_COUNT)
|
||||
return;
|
||||
|
||||
//no worker there, just do it immediately on this thread instead of pushing it to the worker.
|
||||
if (thread && (!com_workerthread[thread] || com_workererror))
|
||||
if (!com_liveworkers[tg] || (tg!=WG_MAIN && com_workererror))
|
||||
{
|
||||
func(ctx, data, a, b);
|
||||
return;
|
||||
|
@ -4837,19 +4788,19 @@ void COM_AddWork(int thread, void(*func)(void *ctx, void *data, size_t a, size_t
|
|||
work->b = b;
|
||||
|
||||
//queue it (fifo)
|
||||
Sys_LockConditional(com_workercondition[thread]);
|
||||
if (com_work_tail[thread])
|
||||
Sys_LockConditional(com_workercondition[tg]);
|
||||
if (com_work_tail[tg])
|
||||
{
|
||||
com_work_tail[thread]->next = work;
|
||||
com_work_tail[thread] = work;
|
||||
com_work_tail[tg]->next = work;
|
||||
com_work_tail[tg] = work;
|
||||
}
|
||||
else
|
||||
com_work_head[thread] = com_work_tail[thread] = work;
|
||||
com_work_head[tg] = com_work_tail[tg] = work;
|
||||
|
||||
// Sys_Printf("%x: Queued work %p (%s)\n", thread, work->ctx, work->ctx?(char*)work->ctx:"?");
|
||||
|
||||
Sys_ConditionSignal(com_workercondition[thread]);
|
||||
Sys_UnlockConditional(com_workercondition[thread]);
|
||||
Sys_ConditionSignal(com_workercondition[tg]);
|
||||
Sys_UnlockConditional(com_workercondition[tg]);
|
||||
|
||||
// if (!com_workerthread[thread])
|
||||
// while(COM_DoWork(thread, false))
|
||||
|
@ -4857,72 +4808,157 @@ void COM_AddWork(int thread, void(*func)(void *ctx, void *data, size_t a, size_t
|
|||
}
|
||||
//leavelocked = false == poll mode.
|
||||
//leavelocked = true == safe sleeping
|
||||
qboolean COM_DoWork(int thread, qboolean leavelocked)
|
||||
qboolean COM_DoWork(int tg, qboolean leavelocked)
|
||||
{
|
||||
struct com_work_s *work;
|
||||
if (tg >= WG_COUNT)
|
||||
return false;
|
||||
if (!leavelocked)
|
||||
{
|
||||
//skip the locks if it looks like we can be lazy.
|
||||
if (!com_work_head[thread])
|
||||
if (!com_work_head[tg])
|
||||
return false;
|
||||
Sys_LockConditional(com_workercondition[thread]);
|
||||
Sys_LockConditional(com_workercondition[tg]);
|
||||
}
|
||||
work = com_work_head[thread];
|
||||
work = com_work_head[tg];
|
||||
if (work)
|
||||
com_work_head[thread] = work->next;
|
||||
if (!com_work_head[thread])
|
||||
com_work_head[thread] = com_work_tail[thread] = NULL;
|
||||
com_work_head[tg] = work->next;
|
||||
if (!com_work_head[tg])
|
||||
com_work_head[tg] = com_work_tail[tg] = NULL;
|
||||
|
||||
if (work)
|
||||
{
|
||||
// Sys_Printf("%x: Doing work %p (%s)\n", thread, work->ctx, work->ctx?(char*)work->ctx:"?");
|
||||
Sys_UnlockConditional(com_workercondition[thread]);
|
||||
Sys_UnlockConditional(com_workercondition[tg]);
|
||||
|
||||
work->func(work->ctx, work->data, work->a, work->b);
|
||||
Z_Free(work);
|
||||
|
||||
if (leavelocked)
|
||||
Sys_LockConditional(com_workercondition[thread]);
|
||||
Sys_LockConditional(com_workercondition[tg]);
|
||||
|
||||
return true; //did something, check again
|
||||
}
|
||||
|
||||
if (!leavelocked)
|
||||
Sys_UnlockConditional(com_workercondition[thread]);
|
||||
Sys_UnlockConditional(com_workercondition[tg]);
|
||||
|
||||
//nothing going on, if leavelocked then noone can add anything until we sleep.
|
||||
return false;
|
||||
}
|
||||
static void COM_WorkerSync_StopWorker(void *ctx, void *data, size_t a, size_t b)
|
||||
static void COM_WorkerSync_ThreadAck(void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
com_workerdone[a] = true;
|
||||
int us;
|
||||
int *ackbuf = ctx;
|
||||
|
||||
Sys_LockConditional(com_workercondition[WG_MAIN]);
|
||||
//find out which worker we are, and flag ourselves as having acked the main thread to clean us up
|
||||
for (us = 0; us < WORKERTHREADS; us++)
|
||||
{
|
||||
if (com_worker[us].thread && Sys_IsThread(com_worker[us].thread))
|
||||
{
|
||||
ackbuf[us] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*(int*)data += 1;
|
||||
//and tell the main thread it can stop being idle now
|
||||
Sys_ConditionSignal(com_workercondition[WG_MAIN]);
|
||||
Sys_UnlockConditional(com_workercondition[WG_MAIN]);
|
||||
}
|
||||
static void COM_WorkerSync_SignalMain(void *ctx, void *data, size_t a, size_t b)
|
||||
/*static void COM_WorkerSync_SignalMain(void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
Sys_LockConditional(com_workercondition[a]);
|
||||
com_workerdone[a] = true;
|
||||
Sys_ConditionSignal(com_workercondition[a]);
|
||||
Sys_UnlockConditional(com_workercondition[a]);
|
||||
}*/
|
||||
static void COM_WorkerSync_WorkerStopped(void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
struct com_worker_s *thread = ctx;
|
||||
if (thread->thread)
|
||||
{
|
||||
//the worker signaled us then stopped looping
|
||||
Sys_WaitOnThread(thread->thread);
|
||||
thread->thread = NULL;
|
||||
|
||||
Sys_LockConditional(com_workercondition[b]);
|
||||
com_liveworkers[b] -= 1;
|
||||
Sys_UnlockConditional(com_workercondition[b]);
|
||||
}
|
||||
else
|
||||
Con_Printf("worker thread died twice?\n");
|
||||
|
||||
//if that was the last thread, make sure any work pending for that group is completed.
|
||||
if (!com_liveworkers[b])
|
||||
{
|
||||
while(COM_DoWork(b, false))
|
||||
;
|
||||
}
|
||||
}
|
||||
static int COM_WorkerThread(void *arg)
|
||||
{
|
||||
int thread = (void**)arg - com_workerthread;
|
||||
Sys_LockConditional(com_workercondition[thread]);
|
||||
do
|
||||
struct com_worker_s *thread = arg;
|
||||
int group = WG_LOADER;
|
||||
Sys_LockConditional(com_workercondition[group]);
|
||||
com_liveworkers[group]++;
|
||||
for(;;)
|
||||
{
|
||||
while(COM_DoWork(thread, true))
|
||||
while(COM_DoWork(group, true))
|
||||
;
|
||||
if (com_workerdone[thread])
|
||||
if (thread->request) //flagged from some work
|
||||
{
|
||||
if (thread->request == WR_DIE)
|
||||
break;
|
||||
if (thread->request == WR_ACK)
|
||||
{
|
||||
thread->request = WR_NONE;
|
||||
thread->ackseq = com_workeracksequence;
|
||||
Sys_UnlockConditional(com_workercondition[group]);
|
||||
Sys_ConditionBroadcast(com_workercondition[WG_MAIN]); //try to wake up whoever wanted us to ack them
|
||||
Sys_LockConditional(com_workercondition[group]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (!Sys_ConditionWait(com_workercondition[group]))
|
||||
break;
|
||||
} while (Sys_ConditionWait(com_workercondition[thread]));
|
||||
Sys_UnlockConditional(com_workercondition[thread]);
|
||||
}
|
||||
Sys_UnlockConditional(com_workercondition[group]);
|
||||
|
||||
//no more work please...
|
||||
*(void**)arg = NULL;
|
||||
//and wake up main thread
|
||||
COM_WorkerSync_SignalMain(NULL, NULL, 0, 0);
|
||||
//and wake up main thread to clean up our handle
|
||||
COM_AddWork(WG_MAIN, COM_WorkerSync_WorkerStopped, thread, NULL, 0, group);
|
||||
return 0;
|
||||
}
|
||||
static void Sys_ErrorThread(void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
//posted to main thread from a worker.
|
||||
Sys_Error(data);
|
||||
}
|
||||
void COM_WorkerAbort(char *message)
|
||||
{
|
||||
int group = -1;
|
||||
int us;
|
||||
if (Sys_IsMainThread())
|
||||
return;
|
||||
com_workererror = true;
|
||||
|
||||
if (!com_workercondition[WG_MAIN])
|
||||
return; //Sys_IsMainThread was probably called too early...
|
||||
|
||||
//find out which worker we are, and tell the main thread to clean us up
|
||||
for (us = 0; us < WORKERTHREADS; us++)
|
||||
if (com_worker[us].thread && Sys_IsThread(com_worker[us].thread))
|
||||
{
|
||||
group = WG_LOADER;
|
||||
COM_AddWork(WG_MAIN, COM_WorkerSync_WorkerStopped, &com_worker[us], NULL, 0, group);
|
||||
break;
|
||||
}
|
||||
|
||||
//now tell the main thread that it should be crashing, and why.
|
||||
COM_AddWork(WG_MAIN, Sys_ErrorThread, NULL, Z_StrDup(message), 0, 0);
|
||||
|
||||
Sys_ThreadAbort();
|
||||
}
|
||||
|
||||
#ifndef COM_AssertMainThread
|
||||
void COM_AssertMainThread(const char *msg)
|
||||
|
@ -4936,49 +4972,30 @@ void COM_AssertMainThread(const char *msg)
|
|||
void COM_DestroyWorkerThread(void)
|
||||
{
|
||||
int i;
|
||||
COM_WorkerFullSync();
|
||||
if (!com_resourcemutex)
|
||||
return;
|
||||
// com_workererror = false;
|
||||
Sys_LockConditional(com_workercondition[WG_LOADER]);
|
||||
for (i = 0; i < WORKERTHREADS; i++)
|
||||
{
|
||||
if (com_workerthread[i])
|
||||
{
|
||||
void *thread = com_workerthread[i];
|
||||
com_workerdone[0] = false;
|
||||
//send it the terminate message
|
||||
COM_AddWork(i, COM_WorkerSync_StopWorker, NULL, NULL, i, 0);
|
||||
com_worker[i].request = WR_DIE; //flag them all to die
|
||||
Sys_ConditionBroadcast(com_workercondition[WG_LOADER]); //and make sure they ALL wake up
|
||||
Sys_UnlockConditional(com_workercondition[WG_LOADER]);
|
||||
|
||||
//wait for the response while servicing anything that it might be waiting for.
|
||||
Sys_LockConditional(com_workercondition[0]);
|
||||
do
|
||||
{
|
||||
if (com_workererror)
|
||||
break;
|
||||
while(COM_DoWork(0, true))
|
||||
;
|
||||
if (com_workerdone[0])
|
||||
break;
|
||||
} while (Sys_ConditionWait(com_workercondition[0]));
|
||||
Sys_UnlockConditional(com_workercondition[0]);
|
||||
while(COM_DoWork(WG_LOADER, false)) //finish any work that got posted to it that it neglected to finish.
|
||||
;
|
||||
while(COM_DoWork(WG_MAIN, false))
|
||||
;
|
||||
|
||||
//and now that we know its going down and will not wait any more, we can block for its final moments
|
||||
Sys_WaitOnThread(thread);
|
||||
COM_WorkerFullSync();
|
||||
|
||||
//finish any work that got posted to it that it neglected to finish.
|
||||
while(COM_DoWork(i, true))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < WORKERTHREADS; i++)
|
||||
for (i = 0; i < WG_COUNT; i++)
|
||||
{
|
||||
if (com_workercondition[i])
|
||||
Sys_DestroyConditional(com_workercondition[i]);
|
||||
com_workercondition[i] = NULL;
|
||||
com_workerthread[i] = NULL;
|
||||
}
|
||||
|
||||
if (com_resourcemutex)
|
||||
Sys_DestroyMutex(com_resourcemutex);
|
||||
Sys_DestroyMutex(com_resourcemutex);
|
||||
com_resourcemutex = NULL;
|
||||
}
|
||||
|
||||
|
@ -4988,36 +5005,56 @@ void COM_WorkerFullSync(void)
|
|||
qboolean repeat;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < WORKERTHREADS; i++)
|
||||
{
|
||||
if (!com_workerthread[i])
|
||||
continue;
|
||||
while(COM_DoWork(WG_MAIN, false))
|
||||
;
|
||||
|
||||
//main thread asks worker thread to set main thread's 'done' flag.
|
||||
//the worker might be posting work to the main thread and back (shaders with texures) so make sure that the only work we do before the reply is the reply itself.
|
||||
do
|
||||
if (!com_liveworkers[WG_LOADER])
|
||||
return;
|
||||
|
||||
com_workeracksequence++;
|
||||
|
||||
Sys_LockConditional(com_workercondition[WG_MAIN]);
|
||||
do
|
||||
{
|
||||
if (!COM_HasWork())
|
||||
{
|
||||
int cmds = 0;
|
||||
com_workerdone[0] = false;
|
||||
repeat = COM_HasWork();
|
||||
COM_AddWork(i, COM_WorkerSync_SignalMain, NULL, NULL, 0, 0);
|
||||
Sys_LockConditional(com_workercondition[0]);
|
||||
do
|
||||
Sys_UnlockConditional(com_workercondition[WG_MAIN]);
|
||||
Sys_LockConditional(com_workercondition[WG_LOADER]);
|
||||
repeat = false;
|
||||
for (i = 0; i < WORKERTHREADS; i++)
|
||||
{
|
||||
if (com_workererror)
|
||||
break;
|
||||
while(COM_DoWork(0, true))
|
||||
cmds++;
|
||||
if (com_workerdone[0])
|
||||
break;
|
||||
} while (Sys_ConditionWait(com_workercondition[0]));
|
||||
Sys_UnlockConditional(com_workercondition[0]);
|
||||
if (com_workererror)
|
||||
break;
|
||||
if (cmds > 1)
|
||||
repeat = true;
|
||||
} while (COM_DoWork(0, false) || repeat); //outer loop ensures there isn't anything pingponging between
|
||||
}
|
||||
if (com_worker[i].ackseq != com_workeracksequence && com_worker[i].request == WR_NONE)
|
||||
{
|
||||
com_worker[i].request = WR_ACK;
|
||||
repeat = true;
|
||||
}
|
||||
}
|
||||
if (repeat) //we're unable to signal a specific thread due to only having one condition. oh well. WAKE UP GUYS!
|
||||
Sys_ConditionBroadcast(com_workercondition[WG_LOADER]);
|
||||
Sys_UnlockConditional(com_workercondition[WG_LOADER]);
|
||||
Sys_LockConditional(com_workercondition[WG_MAIN]);
|
||||
}
|
||||
|
||||
repeat = COM_DoWork(WG_MAIN, true);
|
||||
|
||||
if (repeat)
|
||||
{ //if we just did something, we may have posted something new to a worker... bum.
|
||||
com_workeracksequence++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < WORKERTHREADS; i++)
|
||||
{
|
||||
if (com_worker[i].thread && com_worker[i].ackseq != com_workeracksequence)
|
||||
repeat = true;
|
||||
}
|
||||
if (repeat)
|
||||
Sys_ConditionWait(com_workercondition[WG_MAIN]);
|
||||
}
|
||||
if (com_workererror)
|
||||
break;
|
||||
} while(repeat);
|
||||
Sys_UnlockConditional(com_workercondition[WG_MAIN]);
|
||||
}
|
||||
|
||||
//main thread wants a specific object to be prioritised.
|
||||
|
@ -5032,18 +5069,20 @@ void COM_WorkerPartialSync(void *priorityctx, int *address, int value)
|
|||
|
||||
// Con_Printf("waiting for %p %s\n", priorityctx, priorityctx);
|
||||
|
||||
COM_DoWork(WG_MAIN, false);
|
||||
|
||||
//boost the priority of the object that we're waiting for on the other thread, if we can find it.
|
||||
//this avoids waiting for everything.
|
||||
//if we can't find it, then its probably currently being processed anyway.
|
||||
//main thread is meant to do all loadstate value changes anyway, ensuring that we're woken up properly in this case.
|
||||
if (priorityctx)
|
||||
{
|
||||
unsigned int thread;
|
||||
unsigned int grp;
|
||||
qboolean found = false;
|
||||
for (thread = 1; thread < WORKERTHREADS && !found; thread++)
|
||||
for (grp = WG_LOADER; grp < WG_MAIN && !found; grp++)
|
||||
{
|
||||
Sys_LockConditional(com_workercondition[thread]);
|
||||
for (link = &com_work_head[thread], work = NULL; *link; link = &(*link)->next)
|
||||
Sys_LockConditional(com_workercondition[grp]);
|
||||
for (link = &com_work_head[grp], work = NULL; *link; link = &(*link)->next)
|
||||
{
|
||||
prev = work;
|
||||
work = *link;
|
||||
|
@ -5052,30 +5091,30 @@ void COM_WorkerPartialSync(void *priorityctx, int *address, int value)
|
|||
|
||||
*link = work->next;
|
||||
if (!work->next)
|
||||
com_work_tail[thread] = prev;
|
||||
com_work_tail[grp] = prev;
|
||||
//link it in at the head, so its the next thing seen.
|
||||
work->next = com_work_head[thread];
|
||||
com_work_head[thread] = work;
|
||||
work->next = com_work_head[grp];
|
||||
com_work_head[grp] = work;
|
||||
if (!work->next)
|
||||
com_work_tail[thread] = work;
|
||||
com_work_tail[grp] = work;
|
||||
found = true;
|
||||
|
||||
break; //found it, nothing else to do.
|
||||
}
|
||||
}
|
||||
//we've not actually added any work, so no need to signal
|
||||
Sys_UnlockConditional(com_workercondition[thread]);
|
||||
Sys_UnlockConditional(com_workercondition[grp]);
|
||||
}
|
||||
if (!found)
|
||||
Con_DPrintf("Might be in for a long wait for %s\n", (char*)priorityctx);
|
||||
}
|
||||
|
||||
Sys_LockConditional(com_workercondition[0]);
|
||||
Sys_LockConditional(com_workercondition[WG_MAIN]);
|
||||
do
|
||||
{
|
||||
if (com_workererror)
|
||||
break;
|
||||
while(COM_DoWork(0, true))
|
||||
while(COM_DoWork(WG_MAIN, true))
|
||||
{
|
||||
//give up as soon as we're done
|
||||
if (*address != value)
|
||||
|
@ -5084,8 +5123,8 @@ void COM_WorkerPartialSync(void *priorityctx, int *address, int value)
|
|||
//if our object's state has changed, we're done
|
||||
if (*address != value)
|
||||
break;
|
||||
} while (Sys_ConditionWait(com_workercondition[0]));
|
||||
Sys_UnlockConditional(com_workercondition[0]);
|
||||
} while (Sys_ConditionWait(com_workercondition[WG_MAIN]));
|
||||
Sys_UnlockConditional(com_workercondition[WG_MAIN]);
|
||||
|
||||
// Con_Printf("Waited %f for %s\n", Sys_DoubleTime() - time1, priorityctx);
|
||||
}
|
||||
|
@ -5094,7 +5133,7 @@ static void COM_WorkerPing(void *ctx, void *data, size_t a, size_t b)
|
|||
{
|
||||
double *timestamp = data;
|
||||
if (!b)
|
||||
COM_AddWork(0, COM_WorkerPing, ctx, data, 0, 1);
|
||||
COM_AddWork(WG_MAIN, COM_WorkerPing, ctx, data, 0, 1);
|
||||
else
|
||||
{
|
||||
Con_Printf("Ping: %g\n", Sys_DoubleTime() - *timestamp);
|
||||
|
@ -5102,35 +5141,66 @@ static void COM_WorkerPing(void *ctx, void *data, size_t a, size_t b)
|
|||
}
|
||||
static void COM_WorkerTest_f(void)
|
||||
{
|
||||
if (com_workerthread)
|
||||
{
|
||||
double *timestamp = Z_Malloc(sizeof(*timestamp));
|
||||
*timestamp = Sys_DoubleTime();
|
||||
COM_AddWork(1, COM_WorkerPing, NULL, timestamp, 0, 0);
|
||||
}
|
||||
else
|
||||
Con_Printf("Worker is not active.\n");
|
||||
double *timestamp = Z_Malloc(sizeof(*timestamp));
|
||||
*timestamp = Sys_DoubleTime();
|
||||
COM_AddWork(WG_LOADER, COM_WorkerPing, NULL, timestamp, 0, 0);
|
||||
}
|
||||
|
||||
static void QDECL COM_WorkerCount_Change(cvar_t *var, char *oldvalue)
|
||||
{
|
||||
int i, count = var->ival;
|
||||
|
||||
cvar_t worker_flush = CVARD("worker_flush", "1", "If set, process the entire load queue, loading stuff faster but at the risk of stalling.");
|
||||
if (!*var->string)
|
||||
{
|
||||
count = 4;
|
||||
}
|
||||
|
||||
//try to respond to any kill requests now, so we don't get surprised by the cvar changing too often.
|
||||
while(COM_DoWork(WG_MAIN, false))
|
||||
;
|
||||
|
||||
for (i = 0; i < WORKERTHREADS; i++)
|
||||
{
|
||||
if (i >= count)
|
||||
{
|
||||
//higher thread indexes need to die.
|
||||
com_worker[i].request = WR_DIE; //flag them all to die
|
||||
}
|
||||
else
|
||||
{
|
||||
//lower thread indexes need to be created
|
||||
if (!com_worker[i].thread)
|
||||
{
|
||||
com_worker[i].request = WR_NONE;
|
||||
com_worker[i].thread = Sys_CreateThread(va("loadworker_%i", i), COM_WorkerThread, &com_worker[i], 0, 256*1024);
|
||||
}
|
||||
}
|
||||
}
|
||||
Sys_ConditionBroadcast(com_workercondition[WG_LOADER]); //and make sure they ALL wake up to check their new death values.
|
||||
}
|
||||
cvar_t worker_flush = CVARD("worker_flush", "1", "If set, process the entire load queue, loading stuff faster but at the risk of stalling the main thread.");
|
||||
cvar_t worker_count = CVARFDC("worker_count", "", CVAR_NOTFROMSERVER, "Specifies the number of worker threads to utilise.", COM_WorkerCount_Change);
|
||||
static void COM_InitWorkerThread(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
//in theory, we could run multiple workers, signalling a different one in turn for each bit of work.
|
||||
com_resourcemutex = Sys_CreateMutex();
|
||||
for (i = 0; i < WORKERTHREADS; i++)
|
||||
for (i = 0; i < WG_COUNT; i++)
|
||||
{
|
||||
com_workercondition[i] = Sys_CreateConditional();
|
||||
}
|
||||
if (!COM_CheckParm("-noworker"))
|
||||
com_liveworkers[WG_MAIN] = 1;
|
||||
|
||||
//technically its ready now...
|
||||
|
||||
if (COM_CheckParm("-noworker"))
|
||||
{
|
||||
for (i = 1; i < WORKERTHREADS; i++)
|
||||
{
|
||||
com_workerthread[i] = Sys_CreateThread(va("loadworker_%i", i), COM_WorkerThread, &com_workerthread[i], 0, 256*1024);
|
||||
}
|
||||
worker_count.string = "0";
|
||||
worker_count.flags |= CVAR_NOSET;
|
||||
}
|
||||
Cvar_Register(&worker_count, NULL);
|
||||
Cvar_ForceCallback(&worker_count);
|
||||
|
||||
Cmd_AddCommand ("worker_test", COM_WorkerTest_f);
|
||||
Cvar_Register(&worker_flush, NULL);
|
||||
|
|
|
@ -429,10 +429,16 @@ typedef struct {
|
|||
} flocation_t;
|
||||
struct vfsfile_s;
|
||||
|
||||
typedef enum {FSLFRT_IFFOUND, FSLFRT_LENGTH, FSLFRT_DEPTH_OSONLY, FSLFRT_DEPTH_ANYPATH} FSLF_ReturnType_e;
|
||||
#define FSLF_IFFOUND 0 //returns true (found) / false (not found)
|
||||
#define FSLF_DEPTH_EXPLICIT 1 //retrieves relative depth (ie: lower = higher priority) for determining which gamedir a file was from
|
||||
#define FSLF_DEPTH_INEXPLICIT 2 //depth is incremented for EVERY package, not just system/explicit paths.
|
||||
#define FSLF_SECUREONLY (1u<<4) //ignore files from downloaded packages (ie: configs)
|
||||
#define FSLF_DONTREFERENCE (1u<<5) //don't add any reference flags to packages
|
||||
#define FSLF_IGNOREPURE (1u<<6) //use only the client's package list, ignore any lists obtained from the server (including any reordering)
|
||||
#define FSLF_IGNORELINKS (1u<<7) //ignore any pak/pk3 symlinks. system ones may still be followed.
|
||||
|
||||
//if loc is valid, loc->search is always filled in, the others are filled on success.
|
||||
//returns -1 if couldn't find.
|
||||
int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation_t *loc);
|
||||
int FS_FLocateFile(const char *filename, unsigned int flags, flocation_t *loc);
|
||||
struct vfsfile_s *FS_OpenReadLocation(flocation_t *location);
|
||||
char *FS_WhichPackForLocation(flocation_t *loc, qboolean makereferenced);
|
||||
|
||||
|
@ -442,8 +448,8 @@ char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean
|
|||
qboolean FS_GenCachedPakName(char *pname, char *crc, char *local, int llen); //returns false if the name is invalid.
|
||||
void FS_ReferenceControl(unsigned int refflag, unsigned int resetflags);
|
||||
|
||||
#define COM_FDepthFile(filename,ignorepacks) FS_FLocateFile(filename,ignorepacks?FSLFRT_DEPTH_OSONLY:FSLFRT_DEPTH_ANYPATH, NULL)
|
||||
#define COM_FCheckExists(filename) FS_FLocateFile(filename,FSLFRT_IFFOUND, NULL)
|
||||
#define COM_FDepthFile(filename,ignorepacks) FS_FLocateFile(filename,FSLF_DONTREFERENCE|(ignorepacks?FSLF_DEPTH_EXPLICIT:FSLF_DEPTH_INEXPLICIT), NULL)
|
||||
#define COM_FCheckExists(filename) FS_FLocateFile(filename,FSLF_IFFOUND, NULL)
|
||||
|
||||
typedef struct vfsfile_s
|
||||
{
|
||||
|
|
|
@ -620,10 +620,11 @@ static unsigned int fs_pureseed; //used as a key so the server knows we're obeyi
|
|||
|
||||
int QDECL COM_FileSize(const char *path)
|
||||
{
|
||||
int len;
|
||||
flocation_t loc;
|
||||
len = FS_FLocateFile(path, FSLFRT_LENGTH, &loc);
|
||||
return len;
|
||||
if (FS_FLocateFile(path, FSLF_IFFOUND, &loc))
|
||||
return loc.len;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
//appends a / on the end of the directory if it does not already have one.
|
||||
|
@ -744,7 +745,7 @@ void COM_Locate_f (void)
|
|||
char *f = Cmd_Argv(1);
|
||||
if (strchr(f, '^')) //fte's filesystem is assumed to be utf-8, but that doesn't mean that console input is. and I'm too lazy to utf-8ify the string (in part because markup can be used to exploit ascii assumptions).
|
||||
Con_Printf("Warning: filename contains markup. If this is because of unicode, set com_parseutf8 1\n");
|
||||
if (FS_FLocateFile(f, FSLFRT_LENGTH, &loc)>=0)
|
||||
if (FS_FLocateFile(f, FSLF_IFFOUND, &loc))
|
||||
{
|
||||
if (!*loc.rawname)
|
||||
{
|
||||
|
@ -1000,7 +1001,7 @@ Sets com_filesize and one of handle or file
|
|||
*/
|
||||
//if loc is valid, loc->search is always filled in, the others are filled on success.
|
||||
//returns -1 if couldn't find.
|
||||
int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation_t *loc)
|
||||
int FS_FLocateFile(const char *filename, unsigned int lflags, flocation_t *loc)
|
||||
{
|
||||
int depth=0;
|
||||
searchpath_t *search;
|
||||
|
@ -1026,7 +1027,7 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (com_fs_cache.ival && !com_fschanged)
|
||||
if (com_fs_cache.ival && !com_fschanged && !(lflags & FSLF_IGNOREPURE))
|
||||
{
|
||||
pf = Hash_GetInsensitive(&filesystemhash, filename);
|
||||
if (!pf)
|
||||
|
@ -1035,17 +1036,19 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation
|
|||
else
|
||||
pf = NULL;
|
||||
|
||||
if (com_purepaths && found == FF_NOTFOUND)
|
||||
if (com_purepaths && found == FF_NOTFOUND && !(lflags & FSLF_IGNOREPURE))
|
||||
{
|
||||
//check if its in one of the 'pure' packages. these override the default ones.
|
||||
for (search = com_purepaths ; search ; search = search->nextpure)
|
||||
{
|
||||
depth += ((search->flags & SPF_EXPLICIT) || returntype == FSLFRT_DEPTH_ANYPATH);
|
||||
if ((lflags & FSLF_SECUREONLY) && !(search->flags & SPF_UNTRUSTED))
|
||||
continue;
|
||||
depth += ((search->flags & SPF_EXPLICIT) || (lflags & FSLF_DEPTH_EXPLICIT));
|
||||
fs_finds++;
|
||||
found = search->handle->FindFile(search->handle, loc, filename, pf);
|
||||
if (found)
|
||||
{
|
||||
if (returntype != FSLFRT_DEPTH_OSONLY && returntype != FSLFRT_DEPTH_ANYPATH)
|
||||
if (!(lflags & FSLF_DONTREFERENCE))
|
||||
{
|
||||
if ((search->flags & fs_referencetype) != fs_referencetype)
|
||||
Con_DPrintf("%s became referenced due to %s\n", search->purepath, filename);
|
||||
|
@ -1057,17 +1060,19 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation
|
|||
}
|
||||
}
|
||||
|
||||
if (fs_puremode < 2 && found == FF_NOTFOUND)
|
||||
if (((lflags & FSLF_IGNOREPURE) || fs_puremode < 2) && found == FF_NOTFOUND)
|
||||
{
|
||||
// optionally check the non-pure paths too.
|
||||
for (search = com_searchpaths ; search ; search = search->next)
|
||||
{
|
||||
depth += ((search->flags & SPF_EXPLICIT) || returntype == FSLFRT_DEPTH_ANYPATH);
|
||||
if ((lflags & FSLF_SECUREONLY) && !(search->flags & SPF_UNTRUSTED))
|
||||
continue;
|
||||
depth += ((search->flags & SPF_EXPLICIT) || (lflags & FSLF_DEPTH_EXPLICIT));
|
||||
fs_finds++;
|
||||
found = search->handle->FindFile(search->handle, loc, filename, pf);
|
||||
if (found)
|
||||
{
|
||||
if (returntype != FSLFRT_DEPTH_OSONLY && returntype != FSLFRT_DEPTH_ANYPATH)
|
||||
if (!(lflags & FSLF_DONTREFERENCE))
|
||||
{
|
||||
if ((search->flags & fs_referencetype) != fs_referencetype)
|
||||
Con_DPrintf("%s became referenced due to %s\n", search->purepath, filename);
|
||||
|
@ -1079,7 +1084,7 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation
|
|||
}
|
||||
}
|
||||
fail:
|
||||
if (found == FF_SYMLINK)
|
||||
if (found == FF_SYMLINK && !(lflags & FSLF_IGNORELINKS))
|
||||
{
|
||||
static int blocklink;
|
||||
if (blocklink < 4 && loc->len < MAX_QPATH)
|
||||
|
@ -1125,7 +1130,7 @@ fail:
|
|||
|
||||
//and locate that instead.
|
||||
blocklink++;
|
||||
depth = FS_FLocateFile(mergedname, returntype, loc);
|
||||
depth = FS_FLocateFile(mergedname, lflags, loc);
|
||||
blocklink--;
|
||||
if (!loc->search)
|
||||
Con_Printf("Symlink %s -> %s (%s) is dead\n", filename, targname, mergedname);
|
||||
|
@ -1143,20 +1148,14 @@ fail:
|
|||
else
|
||||
Con_Printf("Failed\n");
|
||||
*/
|
||||
if (returntype == FSLFRT_IFFOUND)
|
||||
return (found != FF_NOTFOUND) && (loc->len != -1);
|
||||
else if (returntype == FSLFRT_LENGTH)
|
||||
{
|
||||
if (found == FF_NOTFOUND)
|
||||
return -1;
|
||||
return loc->len;
|
||||
}
|
||||
else
|
||||
if (lflags & (FSLF_DEPTH_EXPLICIT | FSLF_DEPTH_INEXPLICIT))
|
||||
{
|
||||
if (found == FF_NOTFOUND)
|
||||
return 0x7fffffff;
|
||||
return depth;
|
||||
}
|
||||
else
|
||||
return (found != FF_NOTFOUND) && (loc->len != -1);
|
||||
}
|
||||
|
||||
char *FS_WhichPackForLocation(flocation_t *loc, qboolean makereferenced)
|
||||
|
@ -1704,7 +1703,7 @@ vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative r
|
|||
break;
|
||||
}
|
||||
|
||||
FS_FLocateFile(filename, FSLFRT_IFFOUND, &loc);
|
||||
FS_FLocateFile(filename, FSLF_IFFOUND, &loc);
|
||||
|
||||
if (loc.search)
|
||||
{
|
||||
|
@ -1856,9 +1855,8 @@ qbyte *COM_LoadFile (const char *path, int usehunk, size_t *filesize)
|
|||
qbyte *buf;
|
||||
qofs_t len;
|
||||
flocation_t loc;
|
||||
FS_FLocateFile(path, FSLFRT_LENGTH, &loc);
|
||||
|
||||
if (!loc.search)
|
||||
|
||||
if (!FS_FLocateFile(path, FSLF_IFFOUND, &loc) || !loc.search)
|
||||
return NULL; //wasn't found
|
||||
|
||||
if (loc.len > 0x7fffffff) //don't malloc 5000gb sparse files or anything crazy on a 32bit system...
|
||||
|
@ -2834,7 +2832,7 @@ vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name)
|
|||
if (search)
|
||||
found = search->FindFile(search, &loc, name, NULL);
|
||||
else
|
||||
found = FS_FLocateFile(name, FSLFRT_IFFOUND, &loc);
|
||||
found = FS_FLocateFile(name, FSLF_IFFOUND, &loc);
|
||||
if (found)
|
||||
{
|
||||
f = (search?search:loc.search->handle)->OpenVFS(search?search:loc.search->handle, &loc, "rb");
|
||||
|
@ -2855,7 +2853,7 @@ vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name)
|
|||
if (search)
|
||||
found = search->FindFile(search, &loc, name, NULL);
|
||||
else
|
||||
found = FS_FLocateFile(name, FSLFRT_IFFOUND, &loc);
|
||||
found = FS_FLocateFile(name, FSLF_IFFOUND, &loc);
|
||||
if (found)
|
||||
{
|
||||
f = (search?search:loc.search->handle)->OpenVFS(search?search:loc.search->handle, &loc, "rb");
|
||||
|
@ -2939,13 +2937,19 @@ char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum)
|
|||
int numpaks = 0;
|
||||
searchpath_t *sp;
|
||||
|
||||
FS_FLocateFile("vm/cgame.qvm", FSLFRT_LENGTH, &loc);
|
||||
Q_strncatz(buffer, va("%i ", loc.search->crc_reply), maxlen);
|
||||
basechecksum ^= loc.search->crc_reply;
|
||||
if (FS_FLocateFile("vm/cgame.qvm", FSLF_IFFOUND, &loc))
|
||||
{
|
||||
Q_strncatz(buffer, va("%i ", loc.search->crc_reply), maxlen);
|
||||
basechecksum ^= loc.search->crc_reply;
|
||||
}
|
||||
else Q_strncatz(buffer, va("%i ", 0), maxlen);
|
||||
|
||||
FS_FLocateFile("vm/ui.qvm", FSLFRT_LENGTH, &loc);
|
||||
Q_strncatz(buffer, va("%i ", loc.search->crc_reply), maxlen);
|
||||
basechecksum ^= loc.search->crc_reply;
|
||||
if (FS_FLocateFile("vm/ui.qvm", FSLF_IFFOUND, &loc))
|
||||
{
|
||||
Q_strncatz(buffer, va("%i ", loc.search->crc_reply), maxlen);
|
||||
basechecksum ^= loc.search->crc_reply;
|
||||
}
|
||||
else Q_strncatz(buffer, va("%i ", 0), maxlen);
|
||||
|
||||
Q_strncatz(buffer, "@ ", maxlen);
|
||||
|
||||
|
@ -4509,12 +4513,12 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
|
|||
|
||||
for (i = 0; i < countof(vidfile); i++)
|
||||
{
|
||||
FS_FLocateFile(vidfile[i], FSLFRT_IFFOUND, &loc); //q1
|
||||
FS_FLocateFile(vidfile[i], FSLF_IFFOUND, &loc); //q1
|
||||
vidpath[i] = loc.search?loc.search->handle:NULL;
|
||||
}
|
||||
for (i = 0; i < countof(conffile); i++)
|
||||
{
|
||||
FS_FLocateFile(conffile[i], FSLFRT_IFFOUND, &loc); //q1
|
||||
FS_FLocateFile(conffile[i], FSLF_IFFOUND, &loc); //q1
|
||||
confpath[i] = loc.search?loc.search->handle:NULL;
|
||||
}
|
||||
|
||||
|
@ -4689,7 +4693,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
|
|||
{
|
||||
for (i = 0; i < countof(vidfile); i++)
|
||||
{
|
||||
FS_FLocateFile(vidfile[i], FSLFRT_IFFOUND, &loc);
|
||||
FS_FLocateFile(vidfile[i], FSLF_IFFOUND, &loc);
|
||||
if (vidpath[i] != (loc.search?loc.search->handle:NULL))
|
||||
{
|
||||
vidrestart = true;
|
||||
|
@ -4700,7 +4704,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
|
|||
|
||||
for (i = 0; i < countof(conffile); i++)
|
||||
{
|
||||
FS_FLocateFile(conffile[i], FSLFRT_IFFOUND, &loc);
|
||||
FS_FLocateFile(conffile[i], FSLF_IFFOUND, &loc);
|
||||
if (confpath[i] != (loc.search?loc.search->handle:NULL))
|
||||
{
|
||||
reloadconfigs = true;
|
||||
|
|
|
@ -1365,7 +1365,12 @@ void Plug_Initialise(qboolean fromgamedir)
|
|||
if (!numplugbuiltins)
|
||||
{
|
||||
Cvar_Register(&plug_sbar, "plugins");
|
||||
Cvar_Register(&plug_loaddefault, "plugins");
|
||||
#ifdef SUBSERVERS
|
||||
if (!SSV_IsSubServer())
|
||||
#endif
|
||||
|
||||
Cvar_Register(&plug_loaddefault, "plugins");
|
||||
|
||||
Cmd_AddCommand("plug_closeall", Plug_CloseAll_f);
|
||||
Cmd_AddCommand("plug_close", Plug_Close_f);
|
||||
Cmd_AddCommand("plug_load", Plug_Load_f);
|
||||
|
|
|
@ -2145,7 +2145,7 @@ void QCBUILTIN PF_whichpack (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
qboolean makereferenced = prinst->callargc>1?G_FLOAT(OFS_PARM1):true;
|
||||
flocation_t loc;
|
||||
|
||||
if (FS_FLocateFile(srcname, FSLFRT_IFFOUND, &loc))
|
||||
if (FS_FLocateFile(srcname, FSLF_IFFOUND, &loc))
|
||||
{
|
||||
srcname = FS_WhichPackForLocation(&loc, makereferenced);
|
||||
if (srcname == NULL)
|
||||
|
|
|
@ -844,7 +844,7 @@ enum clcq2_ops_e
|
|||
enum {
|
||||
TE_SPIKE = 0,
|
||||
TE_SUPERSPIKE = 1,
|
||||
TE_GUNSHOT = 2,
|
||||
TE_GUNSHOT = 2, //qw has count byte, nq does not
|
||||
TE_EXPLOSION = 3, //remapped to TEQW_EXPLOSIONNOSPRITE for nq.
|
||||
TE_TAREXPLOSION = 4,
|
||||
TE_LIGHTNING1 = 5,
|
||||
|
@ -869,6 +869,7 @@ enum {
|
|||
TEQW_BEAM = 18, //use the builtin, luke.
|
||||
TEQW_EXPLOSION2 = 19, //use the builtin, luke.
|
||||
TEQW_EXPLOSIONNOSPRITE = 20,
|
||||
TE_GUNSHOT_NQCOMPAT = 21, //nq has count byte, qw does not
|
||||
|
||||
// hexen 2
|
||||
TEH2_STREAM_LIGHTNING_SMALL = 24,
|
||||
|
|
|
@ -23,7 +23,7 @@ int VM_fopen (char *name, int *handle, int fmode, int owner)
|
|||
size_t insize;
|
||||
|
||||
if (!handle)
|
||||
return FS_FLocateFile(name, FSLFRT_IFFOUND, NULL);
|
||||
return FS_FLocateFile(name, FSLF_IFFOUND, NULL);
|
||||
|
||||
*handle = 0;
|
||||
|
||||
|
|
|
@ -354,23 +354,20 @@ qboolean Sys_ConditionWait(void *condv)
|
|||
#endif
|
||||
EnterCriticalSection(&cv->countlock);
|
||||
done = cv->release > 0 && cv->waitgeneration != mygen;
|
||||
LeaveCriticalSection(&cv->countlock);
|
||||
if (done)
|
||||
{
|
||||
cv->waiters--;
|
||||
cv->release--;
|
||||
done = cv->release == 0;
|
||||
if (done)
|
||||
ResetEvent(cv->evnt);
|
||||
LeaveCriticalSection(&cv->countlock);
|
||||
break;
|
||||
}
|
||||
LeaveCriticalSection(&cv->countlock);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&cv->mainlock); // lock as per condition variable definition
|
||||
|
||||
// update waiting count and alert signaling thread that we're done to avoid the deadlock condition
|
||||
EnterCriticalSection(&cv->countlock);
|
||||
cv->waiters--;
|
||||
cv->release--;
|
||||
done = cv->release == 0;
|
||||
LeaveCriticalSection(&cv->countlock);
|
||||
|
||||
if (done)
|
||||
ResetEvent(cv->evnt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -384,7 +381,8 @@ qboolean Sys_ConditionSignal(void *condv)
|
|||
EnterCriticalSection(&cv->countlock);
|
||||
if (cv->waiters > cv->release)
|
||||
{
|
||||
SetEvent(cv->evnt);
|
||||
if (!cv->release)
|
||||
SetEvent(cv->evnt);
|
||||
cv->release++;
|
||||
cv->waitgeneration++;
|
||||
}
|
||||
|
@ -405,7 +403,8 @@ qboolean Sys_ConditionBroadcast(void *condv)
|
|||
EnterCriticalSection(&cv->countlock);
|
||||
if (cv->waiters > 0)
|
||||
{
|
||||
SetEvent(cv->evnt);
|
||||
if (!cv->release)
|
||||
SetEvent(cv->evnt);
|
||||
cv->release = cv->waiters;
|
||||
cv->waitgeneration++;
|
||||
}
|
||||
|
|
|
@ -253,6 +253,7 @@ void QDECL World_ReleaseCollisionMesh(wedict_t *ed);
|
|||
|
||||
void World_Destroy (world_t *w);
|
||||
void World_RBE_Start(world_t *world);
|
||||
void World_RBE_Shutdown(world_t *world);
|
||||
|
||||
|
||||
void World_ClearWorld (world_t *w);
|
||||
|
|
|
@ -1264,7 +1264,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
|
|||
lightdir[2] = 1;
|
||||
}
|
||||
|
||||
if (!r_vertexdlights.ival && r_dynamic.ival)
|
||||
if (!r_vertexdlights.ival && r_dynamic.ival > 0)
|
||||
{
|
||||
float *org = e->origin;
|
||||
if (e->flags & RF_WEAPONMODEL)
|
||||
|
|
|
@ -4870,7 +4870,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
// r_refdef.waterheight = DotProduct(batch->mesh[0]->xyz_array[0], batch->mesh[0]->normals_array[0]);
|
||||
|
||||
r_refdef.recurse+=1; //paranoid, should stop potential infinite loops
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_RIPPLE, SHADER_SORT_RIPPLE);
|
||||
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_RIPPLE, SHADER_SORT_RIPPLE);
|
||||
r_refdef.recurse-=1;
|
||||
GLBE_FBO_Pop(oldfbo);
|
||||
|
||||
|
@ -4886,25 +4886,24 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
}
|
||||
}
|
||||
|
||||
void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop)
|
||||
void GLBE_SubmitMeshes (batch_t **worldbatches, int start, int stop)
|
||||
{
|
||||
model_t *model = cl.worldmodel;
|
||||
int i;
|
||||
int portaldepth = r_portalrecursion.ival;
|
||||
|
||||
for (i = start; i <= stop; i++)
|
||||
{
|
||||
if (drawworld)
|
||||
if (worldbatches)
|
||||
{
|
||||
if (i == SHADER_SORT_PORTAL && r_refdef.recurse < portaldepth)
|
||||
{
|
||||
GLBE_SubmitMeshesPortals(model->batches, shaderstate.mbatches[i]);
|
||||
GLBE_SubmitMeshesPortals(worldbatches, shaderstate.mbatches[i]);
|
||||
|
||||
if (!r_refdef.recurse && r_portalonly.ival)
|
||||
return;
|
||||
}
|
||||
|
||||
GLBE_SubmitMeshesSortList(model->batches[i]);
|
||||
GLBE_SubmitMeshesSortList(worldbatches[i]);
|
||||
}
|
||||
GLBE_SubmitMeshesSortList(shaderstate.mbatches[i]);
|
||||
}
|
||||
|
@ -4941,6 +4940,8 @@ static void BE_UpdateLightmaps(void)
|
|||
continue;
|
||||
if (lm->modified)
|
||||
{
|
||||
int t = lm->rectchange.t; //pull them out now, in the hopes that it'll be more robust with respect to r_dynamic -1
|
||||
int b = lm->rectchange.b;
|
||||
lm->modified = false;
|
||||
if (!TEXVALID(lm->lightmap_texture))
|
||||
{
|
||||
|
@ -4957,14 +4958,14 @@ static void BE_UpdateLightmaps(void)
|
|||
else
|
||||
{
|
||||
GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture);
|
||||
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, lm->rectchange.t,
|
||||
lm->width, lm->rectchange.h, glformat, gltype,
|
||||
lm->lightmaps+(lm->rectchange.t) *lm->width*lightmap_bytes);
|
||||
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, t,
|
||||
lm->width, b-t, glformat, gltype,
|
||||
lm->lightmaps+t *lm->width*lightmap_bytes);
|
||||
}
|
||||
lm->rectchange.l = lm->width;
|
||||
lm->rectchange.t = lm->height;
|
||||
lm->rectchange.h = 0;
|
||||
lm->rectchange.w = 0;
|
||||
lm->rectchange.r = 0;
|
||||
lm->rectchange.b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4990,7 +4991,7 @@ void GLBE_BaseEntTextures(void)
|
|||
batch_t **ob = shaderstate.mbatches;
|
||||
shaderstate.mbatches = batches;
|
||||
BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode);
|
||||
GLBE_SubmitMeshes(false, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1);
|
||||
GLBE_SubmitMeshes(NULL, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1);
|
||||
GLBE_SelectEntity(&r_worldentity);
|
||||
shaderstate.mbatches = ob;
|
||||
}
|
||||
|
@ -5340,7 +5341,7 @@ void GLBE_DrawLightPrePass(qbyte *vis)
|
|||
}
|
||||
/*do portals*/
|
||||
BE_SelectMode(BEM_STANDARD);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_PORTAL);
|
||||
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_PORTAL, SHADER_SORT_PORTAL);
|
||||
|
||||
BE_SelectMode(BEM_DEPTHNORM);
|
||||
if (!shaderstate.depthnormshader)
|
||||
|
@ -5393,7 +5394,7 @@ void GLBE_DrawLightPrePass(qbyte *vis)
|
|||
}
|
||||
|
||||
/*draw surfaces that can be drawn this way*/
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_OPAQUE, SHADER_SORT_OPAQUE);
|
||||
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_OPAQUE, SHADER_SORT_OPAQUE);
|
||||
|
||||
/*reconfigure - now drawing diffuse light info using the previous fb image as a source image*/
|
||||
GLBE_FBO_Sources(shaderstate.tex_normals, r_nulltex);
|
||||
|
@ -5405,7 +5406,7 @@ void GLBE_DrawLightPrePass(qbyte *vis)
|
|||
|
||||
GLBE_SelectEntity(&r_worldentity);
|
||||
/*now draw the prelights*/
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PRELIGHT, SHADER_SORT_PRELIGHT);
|
||||
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_PRELIGHT, SHADER_SORT_PRELIGHT);
|
||||
|
||||
/*final reconfigure - now drawing final surface data onto true framebuffer*/
|
||||
GLBE_FBO_Pop(oldfbo);
|
||||
|
@ -5414,7 +5415,7 @@ void GLBE_DrawLightPrePass(qbyte *vis)
|
|||
|
||||
/*now draw the postlight passes (this includes blended stuff which will NOT be lit)*/
|
||||
GLBE_SelectEntity(&r_worldentity);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_SKY, SHADER_SORT_NEAREST);
|
||||
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_SKY, SHADER_SORT_NEAREST);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
/*regular lighting now*/
|
||||
|
@ -5426,7 +5427,7 @@ void GLBE_DrawLightPrePass(qbyte *vis)
|
|||
qglClearColor (1,0,0,1);
|
||||
}
|
||||
|
||||
void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
|
||||
void GLBE_DrawWorld (batch_t **worldbatches, qbyte *vis)
|
||||
{
|
||||
extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_lightmaps;
|
||||
batch_t *batches[SHADER_SORT_COUNT];
|
||||
|
@ -5479,7 +5480,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
|
|||
GLBE_SelectEntity(&r_worldentity);
|
||||
|
||||
BE_UpdateLightmaps();
|
||||
if (drawworld)
|
||||
if (worldbatches)
|
||||
{
|
||||
if (gl_overbright.modified)
|
||||
{
|
||||
|
@ -5493,7 +5494,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
|
|||
}
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
if (drawworld && r_shadow_realtime_world.ival)
|
||||
if (worldbatches && r_shadow_realtime_world.ival)
|
||||
shaderstate.identitylighting = r_shadow_realtime_world_lightmaps.value;
|
||||
else
|
||||
#endif
|
||||
|
@ -5517,11 +5518,11 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
|
|||
BE_SelectMode(BEM_STANDARD);
|
||||
|
||||
RSpeedRemark();
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
|
||||
GLBE_SubmitMeshes(worldbatches, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
|
||||
RSpeedEnd(RSPEED_WORLD);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
if (drawworld)
|
||||
if (worldbatches)
|
||||
{
|
||||
RSpeedRemark();
|
||||
TRACE(("GLBE_DrawWorld: drawing lights\n"));
|
||||
|
@ -5535,7 +5536,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
|
|||
|
||||
shaderstate.identitylighting = 1;
|
||||
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_DECAL, SHADER_SORT_NEAREST);
|
||||
GLBE_SubmitMeshes(worldbatches, SHADER_SORT_DECAL, SHADER_SORT_NEAREST);
|
||||
|
||||
/* if (r_refdef.gfog_alpha)
|
||||
{
|
||||
|
@ -5550,7 +5551,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
|
|||
{
|
||||
BE_SelectMode(BEM_WIREFRAME);
|
||||
qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
GLBE_SubmitMeshes(worldbatches, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
BE_SelectMode(BEM_STANDARD);
|
||||
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
@ -5559,14 +5560,14 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
|
|||
}
|
||||
else
|
||||
{
|
||||
GLBE_SubmitMeshes(false, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
GLBE_SubmitMeshes(NULL, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
|
||||
#ifdef GL_LINE //no gles
|
||||
if (r_wireframe.ival && qglPolygonMode)
|
||||
{
|
||||
BE_SelectMode(BEM_WIREFRAME);
|
||||
qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
GLBE_SubmitMeshes(false, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
GLBE_SubmitMeshes(NULL, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
BE_SelectMode(BEM_STANDARD);
|
||||
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
|
|
@ -854,7 +854,7 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, const char *fontfil
|
|||
}
|
||||
|
||||
error = FT_Err_Cannot_Open_Resource;
|
||||
if (FS_FLocateFile(fontfilename, FSLFRT_LENGTH, &loc)>0)
|
||||
if (FS_FLocateFile(fontfilename, FSLF_IFFOUND, &loc))
|
||||
{
|
||||
if (*loc.rawname && !loc.offset)
|
||||
{
|
||||
|
|
|
@ -512,8 +512,8 @@ static qboolean Terr_InitLightmap(hmsection_t *s, qboolean initialise)
|
|||
lightmap[s->lightmap]->modified = true;
|
||||
lightmap[s->lightmap]->rectchange.l = 0;
|
||||
lightmap[s->lightmap]->rectchange.t = 0;
|
||||
lightmap[s->lightmap]->rectchange.w = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.h = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.r = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.b = HMLMSTRIDE;
|
||||
}
|
||||
|
||||
return s->lightmap>=0;
|
||||
|
@ -1452,8 +1452,8 @@ static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s)
|
|||
lightmap[s->lightmap]->modified = true;
|
||||
lightmap[s->lightmap]->rectchange.l = 0;
|
||||
lightmap[s->lightmap]->rectchange.t = 0;
|
||||
lightmap[s->lightmap]->rectchange.w = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.h = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.r = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.b = HMLMSTRIDE;
|
||||
}
|
||||
for (i = 0; i < SECTHEIGHTSIZE*SECTHEIGHTSIZE; i++)
|
||||
{
|
||||
|
@ -2101,7 +2101,7 @@ qboolean Terrain_LocateSection(char *name, flocation_t *loc)
|
|||
if (!Terr_SaveSection(hm, s, x, y, false))
|
||||
return false;
|
||||
|
||||
return FS_FLocateFile(name, FSLFRT_IFFOUND, loc);
|
||||
return FS_FLocateFile(name, FSLF_IFFOUND, loc);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2240,7 +2240,7 @@ static qboolean Terr_Collect(heightmap_t *hm)
|
|||
#endif
|
||||
|
||||
/*purge all sections, but not root
|
||||
lightmaps only are purged whenever the client rudely kills lightmaps
|
||||
lightmaps only are purged whenever the client rudely kills lightmaps (purges all lightmaps on map changes, to cope with models/maps potentially being unloaded)
|
||||
we'll reload those when its next seen.
|
||||
(lightmaps will already have been destroyed, so no poking them)
|
||||
*/
|
||||
|
@ -2312,6 +2312,7 @@ void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly, qboolean light
|
|||
|
||||
// Con_Printf("PostPurge: %i lm chunks used, %i unused\n", hm->numusedlmsects, hm->numunusedlmsects);
|
||||
}
|
||||
|
||||
void Terr_FreeModel(model_t *mod)
|
||||
{
|
||||
heightmap_t *hm = mod->terrain;
|
||||
|
@ -2354,6 +2355,7 @@ void Terr_FreeModel(model_t *mod)
|
|||
mod->terrain = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SERVERONLY
|
||||
void Terr_DrawTerrainWater(heightmap_t *hm, float *mins, float *maxs, struct hmwater_s *w)
|
||||
{
|
||||
|
@ -3831,7 +3833,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
|
|||
|
||||
if (!s || s->loadstate != TSLS_LOADED)
|
||||
{
|
||||
if ((tr->contents & tr->hm->exteriorcontents) || s->loadstate != TSLS_FAILED)
|
||||
if ((tr->hitcontentsmask & tr->hm->exteriorcontents) || s->loadstate != TSLS_FAILED)
|
||||
{
|
||||
//you're not allowed to walk into sections that have not loaded.
|
||||
//might as well check the entire section instead of just one tile
|
||||
|
@ -4101,6 +4103,7 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec
|
|||
hmtrace.htilesize = hmtrace.hm->sectionsize / (SECTHEIGHTSIZE-1);
|
||||
hmtrace.frac = 1;
|
||||
hmtrace.contents = 0;
|
||||
hmtrace.hitcontentsmask = against;
|
||||
|
||||
hmtrace.plane[0] = 0;
|
||||
hmtrace.plane[1] = 0;
|
||||
|
@ -4389,8 +4392,8 @@ static unsigned char *ted_getlightmap(hmsection_t *s, int idx)
|
|||
lightmap[s->lightmap]->modified = true;
|
||||
lightmap[s->lightmap]->rectchange.l = 0;
|
||||
lightmap[s->lightmap]->rectchange.t = 0;
|
||||
lightmap[s->lightmap]->rectchange.w = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.h = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.r = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.b = HMLMSTRIDE;
|
||||
lm = lightmap[s->lightmap]->lightmaps;
|
||||
lm += ((s->lmy+y) * HMLMSTRIDE + (s->lmx+x)) * lightmap_bytes;
|
||||
return lm;
|
||||
|
@ -4449,8 +4452,8 @@ static void ted_dorelight(heightmap_t *hm)
|
|||
lightmap[s->lightmap]->modified = true;
|
||||
lightmap[s->lightmap]->rectchange.l = 0;
|
||||
lightmap[s->lightmap]->rectchange.t = 0;
|
||||
lightmap[s->lightmap]->rectchange.w = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.h = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.r = HMLMSTRIDE;
|
||||
lightmap[s->lightmap]->rectchange.b = HMLMSTRIDE;
|
||||
}
|
||||
static void ted_sethole(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w)
|
||||
{
|
||||
|
@ -5606,8 +5609,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
|
|||
lm->modified = true;
|
||||
lm->rectchange.l = 0;
|
||||
lm->rectchange.t = 0;
|
||||
lm->rectchange.w = lm->width;
|
||||
lm->rectchange.h = lm->height;
|
||||
lm->rectchange.r = lm->width;
|
||||
lm->rectchange.b = lm->height;
|
||||
|
||||
in = br->faces[j].lightdata;
|
||||
out = lm->lightmaps + (br->faces[j].lmbase[1] * lm->width + br->faces[j].lmbase[0]) * lightmap_bytes;
|
||||
|
@ -6159,6 +6162,21 @@ void CL_Parse_BrushEdit(void)
|
|||
brush.faces = alloca(sizeof(*brush.faces) * brush.numplanes);
|
||||
if (!Brush_Deserialise(hm, &brush))
|
||||
Host_EndGame("CL_Parse_BrushEdit: unparsable brush\n");
|
||||
if (brush.id)
|
||||
{
|
||||
int i;
|
||||
if (cls.demoplayback)
|
||||
Terr_Brush_DeleteId(hm, brush.id);
|
||||
else
|
||||
{
|
||||
for (i = 0; i < hm->numbrushes; i++)
|
||||
{
|
||||
brushes_t *br = &hm->wbrushes[i];
|
||||
if (br->id == brush.id)
|
||||
return; //we already have it. assume we just edited it.
|
||||
}
|
||||
}
|
||||
}
|
||||
Terr_Brush_Insert(mod, hm, &brush);
|
||||
}
|
||||
else
|
||||
|
@ -6608,7 +6626,7 @@ void QCBUILTIN PF_brush_findinvolume(pubprogfuncs_t *prinst, struct globalvars_s
|
|||
}
|
||||
dist = DotProduct (best, in_normals[j]);
|
||||
dist = in_distances[j] - dist;
|
||||
if (dist < 0)
|
||||
if (dist <= 0) //don't find coplanar brushes. add an epsilon if you need this.
|
||||
break;
|
||||
}
|
||||
if (j == in_numplanes)
|
||||
|
@ -6658,6 +6676,10 @@ void Terr_WriteMapFile(vfsfile_t *file, model_t *mod)
|
|||
int i;
|
||||
unsigned int entnum = 0;
|
||||
heightmap_t *hm;
|
||||
|
||||
hm = mod->terrain;
|
||||
if (hm && hm->exteriorcontents != FTECONTENTS_EMPTY)
|
||||
VFS_WRITE(file, "terrain\n", 8);
|
||||
|
||||
start = entities;
|
||||
while(entities)
|
||||
|
@ -7278,13 +7300,36 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force)
|
|||
return hm;
|
||||
}
|
||||
|
||||
#ifndef SERVERONLY
|
||||
void Mod_Terrain_Create_f(void)
|
||||
{
|
||||
int x,y;
|
||||
hmsection_t *s;
|
||||
heightmap_t *hm;
|
||||
char *mname;
|
||||
char *mdata;
|
||||
char *mapdesc;
|
||||
char *skyname;
|
||||
char *groundname;
|
||||
char *watername;
|
||||
char *groundheight;
|
||||
char *waterheight;
|
||||
vfsfile_t *file;
|
||||
model_t mod;
|
||||
memset(&mod, 0, sizeof(mod));
|
||||
if (Cmd_Argc() < 2)
|
||||
{
|
||||
Con_Printf("%s: NAME \"DESCRIPTION\" SKYNAME DEFAULTGROUNDTEX DEFAULTHEIGHT DEFAULTWATER DEFAULTWATERHEIGHT\nGenerates a fresh maps/foo.hmp file. You may wish to edit it with notepad later to customise it. You will need csaddon.dat in order to edit the actual terrain.\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
mname = va("maps/%s.hmp", Cmd_Argv(1));
|
||||
mdata = va(
|
||||
"terrain\n"
|
||||
|
||||
mapdesc = Cmd_Argv(2); if (!*mapdesc) mapdesc = Cmd_Argv(1);
|
||||
skyname = Cmd_Argv(3); if (!*skyname) skyname = "sky1";
|
||||
groundname = Cmd_Argv(4); if (!*groundname) groundname = "default";
|
||||
groundheight = Cmd_Argv(5); if (!*groundheight) groundheight = "0";
|
||||
watername = Cmd_Argv(6); if (!*watername) watername = "";
|
||||
waterheight = Cmd_Argv(7); if (!*waterheight) waterheight = "1024";
|
||||
mod.entities = va(
|
||||
"{\n"
|
||||
"classname \"worldspawn\"\n"
|
||||
"message \"%s\"\n"
|
||||
|
@ -7295,8 +7340,8 @@ void Mod_Terrain_Create_f(void)
|
|||
"_minysegment -2048\n"
|
||||
"_maxxsegment 2048\n"
|
||||
"_maxysegment 2048\n"
|
||||
"//_defaultgroundtexture city4_2\n"
|
||||
"//_defaultwatertexture *water2\n"
|
||||
"//_defaultgroundtexture \"city4_2\"\n"
|
||||
"//_defaultwatertexture \"*water2\"\n"
|
||||
"//_defaultgroundheight -1024\n"
|
||||
"//_defaultwaterheight 0\n" //hurrah, sea level.
|
||||
// "_tiles 64 64 8 8\n"
|
||||
|
@ -7306,10 +7351,51 @@ void Mod_Terrain_Create_f(void)
|
|||
"origin \"0 0 1024\"\n"
|
||||
"}\n"
|
||||
, Cmd_Argv(2));
|
||||
COM_WriteFile(mname, FS_GAMEONLY, mdata, strlen(mdata));
|
||||
|
||||
//FIXME: create 4 sections around the origin
|
||||
mod.type = mod_heightmap;
|
||||
mod.terrain = hm = Z_Malloc(sizeof(*hm));
|
||||
Terr_ParseEntityLump(mod.entities, hm);
|
||||
hm->entitylock = Sys_CreateMutex();
|
||||
ClearLink(&hm->recycle);
|
||||
Q_strncpyz(hm->path, Cmd_Argv(1), sizeof(hm->path));
|
||||
Q_strncpyz(hm->groundshadername, "terrainshader", sizeof(hm->groundshadername));
|
||||
hm->exteriorcontents = FTECONTENTS_SOLID;
|
||||
|
||||
|
||||
for (x = CHUNKBIAS-1; x < CHUNKBIAS+1; x++)
|
||||
for (y = CHUNKBIAS-1; y < CHUNKBIAS+1; y++)
|
||||
Terr_GetSection(hm, x, y, TGS_TRYLOAD|TGS_DEFAULTONFAIL);
|
||||
|
||||
for (x = CHUNKBIAS-1; x < CHUNKBIAS+1; x++)
|
||||
for (y = CHUNKBIAS-1; y < CHUNKBIAS+1; y++)
|
||||
{
|
||||
s = Terr_GetSection(hm, x, y, TGS_WAITLOAD|TGS_DEFAULTONFAIL);
|
||||
if (s && (s->flags & (TSF_EDITED|TSF_DIRTY)))
|
||||
{
|
||||
Terr_InitLightmap(s, false);
|
||||
Terr_SaveSection(hm, s, x, y, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (COM_FCheckExists(mname))
|
||||
{
|
||||
Con_Printf("%s: already exists, not overwriting.\n", mname);
|
||||
return;
|
||||
}
|
||||
FS_CreatePath(mname, FS_GAMEONLY);
|
||||
file = FS_OpenVFS(mname, "wb", FS_GAMEONLY);
|
||||
if (!file)
|
||||
Con_Printf("unable to open %s\n", mname);
|
||||
else
|
||||
{
|
||||
Terr_WriteMapFile(file, &mod);
|
||||
VFS_CLOSE(file);
|
||||
Con_Printf("Wrote %s\n", mname);
|
||||
FS_FlushFSHashWritten();
|
||||
}
|
||||
Terr_FreeModel(&mod);
|
||||
}
|
||||
#endif
|
||||
//reads in the terrain a tile at a time, and writes it out again.
|
||||
//the new version will match our current format version.
|
||||
//this is mostly so I can strip out old format revisions...
|
||||
|
@ -7426,9 +7512,9 @@ void Terr_Init(void)
|
|||
Cvar_Register(&mod_terrain_defaulttexture, "Terrain");
|
||||
Cvar_Register(&mod_terrain_savever, "Terrain");
|
||||
Cmd_AddCommand("mod_terrain_save", Mod_Terrain_Save_f);
|
||||
Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f);
|
||||
Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f);
|
||||
#ifndef SERVERONLY
|
||||
Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f);
|
||||
Cmd_AddCommandD("mod_terrain_convert", Mod_Terrain_Convert_f, "mod_terrain_convert [mapname] [texkill]\nConvert a terrain to the current format. If texkill is specified, only tiles with the named texture will be converted, and tiles with that texture will be stripped. This is a slow operation.");
|
||||
#endif
|
||||
|
||||
|
|
|
@ -82,42 +82,16 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
|
|||
hlmdl_tex_t *tex;
|
||||
hlmdl_bone_t *bones;
|
||||
hlmdl_bonecontroller_t *bonectls;
|
||||
shader_t **shaders;
|
||||
struct hlmodelshaders_s *shaders;
|
||||
void *texmem = NULL;
|
||||
/*~~*/
|
||||
|
||||
|
||||
//checksum the model
|
||||
|
||||
if (mod->engineflags & MDLF_DOCRC)
|
||||
{
|
||||
unsigned short crc;
|
||||
qbyte *p;
|
||||
int len;
|
||||
char st[40];
|
||||
|
||||
QCRC_Init(&crc);
|
||||
for (len = com_filesize, p = buffer; len; len--, p++)
|
||||
QCRC_ProcessByte(&crc, *p);
|
||||
|
||||
sprintf(st, "%d", (int) crc);
|
||||
Info_SetValueForKey (cls.userinfo[0],
|
||||
(mod->engineflags & MDLF_PLAYER) ? pmodel_name : emodel_name,
|
||||
st, sizeof(cls.userinfo[0]));
|
||||
|
||||
if (cls.state >= ca_connected)
|
||||
{
|
||||
CL_SendClientCommand(true, "setinfo %s %d",
|
||||
(mod->engineflags & MDLF_PLAYER) ? pmodel_name : emodel_name,
|
||||
(int)crc);
|
||||
}
|
||||
}
|
||||
|
||||
//load the model into hunk
|
||||
model = ZG_Malloc(&mod->memgroup, sizeof(hlmodelcache_t));
|
||||
|
||||
header = ZG_Malloc(&mod->memgroup, com_filesize);
|
||||
memcpy(header, buffer, com_filesize);
|
||||
header = ZG_Malloc(&mod->memgroup, fsize);
|
||||
memcpy(header, buffer, fsize);
|
||||
|
||||
#if defined(HLSERVER) && (defined(__powerpc__) || defined(__ppc__))
|
||||
//this is to let bigfoot know when he comes to port it all... And I'm lazy.
|
||||
|
@ -148,10 +122,12 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
|
|||
texheader = NULL;
|
||||
if (!header->numtextures)
|
||||
{
|
||||
size_t fz;
|
||||
char texmodelname[MAX_QPATH];
|
||||
COM_StripExtension(mod->name, texmodelname, sizeof(texmodelname));
|
||||
Q_strncatz(texmodelname, "t.mdl", sizeof(texmodelname));
|
||||
//no textures? eesh. They must be stored externally.
|
||||
texheader = texmem = (hlmdl_header_t*)FS_LoadMallocFile(va("%st.mdl", texmodelname));
|
||||
texheader = texmem = (hlmdl_header_t*)FS_LoadMallocFile(texmodelname, &fz);
|
||||
if (texheader)
|
||||
{
|
||||
if (texheader->version != 10)
|
||||
|
@ -184,18 +160,19 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
|
|||
memcpy(bonectls, (hlmdl_bonecontroller_t *) buffer, sizeof(hlmdl_bonecontroller_t)*header->numcontrollers);
|
||||
*/
|
||||
|
||||
model->header = (char *)header - (char *)model;
|
||||
model->texheader = (char *)texheader - (char *)model;
|
||||
model->textures = (char *)tex - (char *)model;
|
||||
model->bones = (char *)bones - (char *)model;
|
||||
model->bonectls = (char *)bonectls - (char *)model;
|
||||
model->header = header;
|
||||
model->bones = bones;
|
||||
model->bonectls = bonectls;
|
||||
|
||||
shaders = ZG_Malloc(&mod->memgroup, texheader->numtextures*sizeof(shader_t));
|
||||
model->shaders = (char *)shaders - (char *)model;
|
||||
model->shaders = shaders;
|
||||
for(i = 0; i < texheader->numtextures; i++)
|
||||
{
|
||||
shaders[i] = R_RegisterSkin(va("%s_%i.tga", mod->name, i), mod->name);
|
||||
shaders[i]->defaulttextures.base = R_LoadTexture8Pal24("", tex[i].w, tex[i].h, (qbyte *) texheader + tex[i].offset, (qbyte *) texheader + tex[i].w * tex[i].h + tex[i].offset, IF_NOALPHA|IF_NOGAMMA);
|
||||
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "%s_%i.tga", mod->name, i);
|
||||
memset(&shaders[i].defaulttex, 0, sizeof(shaders[i].defaulttex));
|
||||
shaders[i].defaulttex.base = Image_GetTexture(shaders[i].name, "", IF_NOALPHA, (qbyte *) texheader + tex[i].offset, (qbyte *) texheader + tex[i].w * tex[i].h + tex[i].offset, tex[i].w, tex[i].h, TF_8PAL24);
|
||||
shaders[i].w = tex[i].w;
|
||||
shaders[i].h = tex[i].h;
|
||||
}
|
||||
|
||||
model->numskins = texheader->numtextures;
|
||||
|
@ -219,7 +196,7 @@ void *Mod_GetHalfLifeModelData(model_t *mod)
|
|||
return NULL; //halflife models only, please
|
||||
|
||||
mc = Mod_Extradata(mod);
|
||||
return (void*)((char*)mc + mc->header);
|
||||
return (void*)mc->header;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -234,7 +211,7 @@ int HLMod_FrameForName(model_t *mod, const char *name)
|
|||
|
||||
mc = Mod_Extradata(mod);
|
||||
|
||||
h = (hlmdl_header_t *)((char *)mc + mc->header);
|
||||
h = mc->header;
|
||||
seqs = (hlmdl_sequencelist_t*)((char*)h+h->seqindex);
|
||||
|
||||
for (i = 0; i < h->numseq; i++)
|
||||
|
@ -256,7 +233,7 @@ int HLMod_BoneForName(model_t *mod, char *name)
|
|||
|
||||
mc = Mod_Extradata(mod);
|
||||
|
||||
h = (hlmdl_header_t *)((char *)mc + mc->header);
|
||||
h = mc->header;
|
||||
bones = (hlmdl_bone_t*)((char*)h+h->boneindex);
|
||||
|
||||
for (i = 0; i < h->numbones; i++)
|
||||
|
@ -278,7 +255,8 @@ int HLMod_BoneForName(model_t *mod, char *name)
|
|||
void HL_CalculateBones
|
||||
(
|
||||
int offset,
|
||||
int frame,
|
||||
int frame1,
|
||||
int frame2,
|
||||
float lerpfrac,
|
||||
vec4_t adjust,
|
||||
hlmdl_bone_t *bone,
|
||||
|
@ -290,7 +268,6 @@ void HL_CalculateBones
|
|||
int i;
|
||||
vec3_t angle;
|
||||
float lerpifrac = 1-lerpfrac;
|
||||
float t;
|
||||
/*~~~~~~~~~~*/
|
||||
|
||||
/* For each vector */
|
||||
|
@ -305,41 +282,30 @@ void HL_CalculateBones
|
|||
if(animation->offset[o] != 0)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
int tempframe = frame;
|
||||
int tempframe;
|
||||
hlmdl_animvalue_t *animvalue = (hlmdl_animvalue_t *) ((qbyte *) animation + animation->offset[o]);
|
||||
short f1, f2;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
/* find values including the required frame */
|
||||
tempframe = frame1;
|
||||
while(animvalue->num.total <= tempframe)
|
||||
{
|
||||
tempframe -= animvalue->num.total;
|
||||
animvalue += animvalue->num.valid + 1;
|
||||
}
|
||||
if(animvalue->num.valid > tempframe)
|
||||
f1 = animvalue[min(animvalue->num.valid-1, tempframe)+1].value;
|
||||
|
||||
/* frame2 is always higher than frame1, so keep searching for it, if its in a different block */
|
||||
tempframe += frame2-frame1;
|
||||
while(animvalue->num.total <= tempframe)
|
||||
{
|
||||
if(animvalue->num.valid > (tempframe + 1))
|
||||
{
|
||||
//we can lerp that
|
||||
t = animvalue[tempframe + 1].value * lerpifrac + lerpfrac * animvalue[tempframe + 2].value;
|
||||
}
|
||||
else
|
||||
t = animvalue[animvalue->num.valid].value;
|
||||
angle[i] = bone->value[o] + t * bone->scale[o];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(animvalue->num.total < tempframe + 1)
|
||||
{
|
||||
angle[i] +=
|
||||
(animvalue[animvalue->num.valid].value * lerpifrac +
|
||||
lerpfrac * animvalue[animvalue->num.valid + 2].value) *
|
||||
bone->scale[o];
|
||||
}
|
||||
else
|
||||
{
|
||||
angle[i] += animvalue[animvalue->num.valid].value * bone->scale[o];
|
||||
}
|
||||
tempframe -= animvalue->num.total;
|
||||
animvalue += animvalue->num.valid + 1;
|
||||
}
|
||||
f2 = animvalue[min(animvalue->num.valid-1, tempframe)+1].value;
|
||||
|
||||
angle[i] += (f1 * lerpifrac + lerpfrac * f2) * bone->scale[o];
|
||||
}
|
||||
|
||||
if(bone->bonecontroller[o] != -1)
|
||||
|
@ -414,32 +380,67 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
|
|||
static vec3_t positions[2];
|
||||
static vec4_t quaternions[2], blended;
|
||||
|
||||
int frame;
|
||||
int frame1, frame2;
|
||||
|
||||
hlmdl_sequencelist_t *sequence = (hlmdl_sequencelist_t *) ((qbyte *) model->header + model->header->seqindex) +
|
||||
((unsigned int)seqnum>=model->header->numseq?0:seqnum);
|
||||
hlmdl_sequencedata_t *sequencedata = (hlmdl_sequencedata_t *)
|
||||
((qbyte *) model->header + model->header->seqgroups) +
|
||||
sequence->seqindex;
|
||||
hlmdl_anim_t *animation = (hlmdl_anim_t *)
|
||||
((qbyte *) model->header + sequencedata->data + sequence->index);
|
||||
hlmdl_anim_t *animation;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
if (sequencedata->name[32])
|
||||
{
|
||||
size_t fz;
|
||||
if (sequence->seqindex >= MAX_ANIM_GROUPS)
|
||||
{
|
||||
Sys_Error("Too many animation sequence cache groups\n");
|
||||
return;
|
||||
}
|
||||
if (!model->animcache[sequence->seqindex])
|
||||
model->animcache[sequence->seqindex] = FS_LoadMallocGroupFile(model->memgroup, sequencedata->name+32, &fz);
|
||||
if (!model->animcache[sequence->seqindex] || model->animcache[sequence->seqindex]->magic != *(int*)"IDSQ" || model->animcache[sequence->seqindex]->version != 10)
|
||||
{
|
||||
Sys_Error("Unable to load %s\n", sequencedata->name+32);
|
||||
return;
|
||||
}
|
||||
animation = (hlmdl_anim_t *)((qbyte*)model->animcache[sequence->seqindex] + sequence->index);
|
||||
}
|
||||
else
|
||||
animation = (hlmdl_anim_t *) ((qbyte *) model->header + sequencedata->data + sequence->index);
|
||||
|
||||
frametime *= sequence->timing;
|
||||
if (frametime < 0)
|
||||
frametime = 0;
|
||||
|
||||
frame = (int)frametime;
|
||||
frametime -= frame;
|
||||
frame1 = (int)frametime;
|
||||
frametime -= frame1;
|
||||
frame2 = frame1+1;
|
||||
|
||||
if (!sequence->numframes)
|
||||
return;
|
||||
if(frame >= sequence->numframes)
|
||||
if(frame1 >= sequence->numframes)
|
||||
{
|
||||
if (sequence->loop)
|
||||
frame %= sequence->numframes;
|
||||
frame1 %= sequence->numframes;
|
||||
else
|
||||
frame = sequence->numframes-1;
|
||||
frame1 = sequence->numframes-1;
|
||||
}
|
||||
if(frame2 >= sequence->numframes)
|
||||
{
|
||||
if (sequence->loop)
|
||||
frame2 %= sequence->numframes;
|
||||
else
|
||||
frame2 = sequence->numframes-1;
|
||||
}
|
||||
|
||||
if (frame2 < frame1)
|
||||
{
|
||||
i = frame2;
|
||||
frame2 = frame1;
|
||||
frame1 = i;
|
||||
frametime = 1-frametime;
|
||||
}
|
||||
|
||||
if (lastbone > model->header->numbones)
|
||||
|
@ -489,10 +490,10 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
|
|||
subblendfrac = 1;
|
||||
for(i = firstbone; i < lastbone; i++)
|
||||
{
|
||||
HL_CalculateBones(0, frame, frametime, model->adjust, model->bones + i, animation + i, positions[0]);
|
||||
HL_CalculateBones(3, frame, frametime, model->adjust, model->bones + i, animation + i, quaternions[0]);
|
||||
HL_CalculateBones(0, frame1, frame2, frametime, model->adjust, model->bones + i, animation + i, positions[0]);
|
||||
HL_CalculateBones(3, frame1, frame2, frametime, model->adjust, model->bones + i, animation + i, quaternions[0]);
|
||||
|
||||
HL_CalculateBones(3, frame, frametime, model->adjust, model->bones + i, animation + i + model->header->numbones, quaternions[1]);
|
||||
HL_CalculateBones(3, frame1, frame2, frametime, model->adjust, model->bones + i, animation + i + model->header->numbones, quaternions[1]);
|
||||
|
||||
QuaternionSlerp(quaternions[0], quaternions[1], subblendfrac, blended);
|
||||
QuaternionGLMatrix(blended[0], blended[1], blended[2], blended[3], matrix);
|
||||
|
@ -522,8 +523,8 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
|
|||
* convert it inside the routine - Inconsistant, but hey.. so's the whole model
|
||||
* format.
|
||||
*/
|
||||
HL_CalculateBones(0, frame, frametime, model->adjust, model->bones + i, animation + i, positions[0]);
|
||||
HL_CalculateBones(3, frame, frametime, model->adjust, model->bones + i, animation + i, quaternions[0]);
|
||||
HL_CalculateBones(0, frame1, frame2, frametime, model->adjust, model->bones + i, animation + i, positions[0]);
|
||||
HL_CalculateBones(3, frame1, frame2, frametime, model->adjust, model->bones + i, animation + i, quaternions[0]);
|
||||
|
||||
QuaternionGLMatrix(quaternions[0][0], quaternions[0][1], quaternions[0][2], quaternions[0][3], matrix);
|
||||
matrix[0][3] = positions[0][0];
|
||||
|
@ -548,6 +549,7 @@ void R_HL_BuildFrame(hlmodel_t *model, hlmdl_model_t *amodel, entity_t *curent,
|
|||
static vecV_t xyz[2048];
|
||||
static vec3_t norm[2048];
|
||||
static vec2_t st[2048];
|
||||
static byte_vec4_t vc[2048];
|
||||
static index_t index[4096];
|
||||
int count;
|
||||
int b;
|
||||
|
@ -568,6 +570,7 @@ void R_HL_BuildFrame(hlmodel_t *model, hlmdl_model_t *amodel, entity_t *curent,
|
|||
mesh->snormals_array = norm; //for rtlighting
|
||||
mesh->tnormals_array = norm; //for rtlighting
|
||||
mesh->indexes = index;
|
||||
mesh->colors4b_array = vc;
|
||||
|
||||
for (b = 0; b < MAX_BONE_CONTROLLERS; b++)
|
||||
model->controller[b] = curent->framestate.bonecontrols[b];
|
||||
|
@ -646,8 +649,14 @@ void R_HL_BuildFrame(hlmodel_t *model, hlmdl_model_t *amodel, entity_t *curent,
|
|||
st[vert][0] = order[2] * tex_s;
|
||||
st[vert][1] = order[3] * tex_t;
|
||||
|
||||
norm[vert][0] = 1;
|
||||
norm[vert][1] = 1;
|
||||
norm[vert][2] = 1;
|
||||
|
||||
vc[vert][0] = 255;
|
||||
vc[vert][1] = 255;
|
||||
vc[vert][2] = 255;
|
||||
vc[vert][3] = 255;
|
||||
|
||||
order += 4;
|
||||
vert++;
|
||||
|
@ -673,12 +682,12 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
|
|||
static mesh_t bmesh, *mptr = &bmesh;
|
||||
|
||||
//general model
|
||||
model.header = (hlmdl_header_t *) ((char *)modelc + modelc->header);
|
||||
// model.texheader = (hlmdl_header_t *) ((char *)modelc + modelc->texheader);
|
||||
model.textures = (hlmdl_tex_t *) ((char *)modelc + modelc->textures);
|
||||
model.bones = (hlmdl_bone_t *) ((char *)modelc + modelc->bones);
|
||||
model.bonectls = (hlmdl_bonecontroller_t *) ((char *)modelc + modelc->bonectls);
|
||||
model.shaders = (shader_t **) ((char *)modelc + modelc->shaders);
|
||||
model.header = modelc->header;
|
||||
model.bones = modelc->bones;
|
||||
model.bonectls = modelc->bonectls;
|
||||
model.shaders = modelc->shaders;
|
||||
model.animcache = modelc->animcache;
|
||||
model.memgroup = &rent->model->memgroup;
|
||||
|
||||
for (body = 0; body < model.header->numbodyparts; body++)
|
||||
{
|
||||
|
@ -696,34 +705,40 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
|
|||
hlmdl_mesh_t *mesh = (hlmdl_mesh_t *) ((qbyte *) model.header + amodel->meshindex) + m;
|
||||
float tex_w;
|
||||
float tex_h;
|
||||
struct hlmodelshaders_s *s;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
if (mesh->skinindex >= modelc->numskins)
|
||||
continue;
|
||||
|
||||
s = &model.shaders[modelc->skins[mesh->skinindex]];
|
||||
|
||||
if (batches)
|
||||
{
|
||||
shader_t *shader;
|
||||
int sort;
|
||||
int sort, j;
|
||||
|
||||
b = BE_GetTempBatch();
|
||||
if (!b)
|
||||
return;
|
||||
|
||||
shader = model.shaders[modelc->skins[mesh->skinindex]];
|
||||
if (!s->shader)
|
||||
{
|
||||
s->shader = R_RegisterSkin(s->name, rent->model->name);
|
||||
R_BuildDefaultTexnums(&s->defaulttex, s->shader);
|
||||
}
|
||||
b->buildmeshes = R_HL_BuildMesh;
|
||||
b->ent = rent;
|
||||
b->mesh = NULL;
|
||||
b->firstmesh = 0;
|
||||
b->meshes = 1;
|
||||
b->skin = &shader->defaulttextures;
|
||||
b->skin = NULL;
|
||||
b->texture = NULL;
|
||||
b->shader = shader;
|
||||
b->shader = s->shader;
|
||||
for (j = 0; j < MAXRLIGHTMAPS; j++)
|
||||
b->lightmap[j] = -1;
|
||||
b->surf_first = batchid;
|
||||
b->flags = 0;
|
||||
sort = shader->sort;
|
||||
sort = b->shader->sort;
|
||||
//fixme: we probably need to force some blend modes based on the surface flags.
|
||||
if (rent->flags & RF_FORCECOLOURMOD)
|
||||
b->flags |= BEF_FORCECOLOURMOD;
|
||||
|
@ -755,8 +770,8 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
|
|||
{
|
||||
if (batchid == b->surf_first)
|
||||
{
|
||||
tex_w = 1.0f / model.textures[modelc->skins[mesh->skinindex]].w;
|
||||
tex_h = 1.0f / model.textures[modelc->skins[mesh->skinindex]].h;
|
||||
tex_w = 1.0f / s->w;
|
||||
tex_h = 1.0f / s->h;
|
||||
|
||||
b->mesh = &mptr;
|
||||
R_HL_BuildFrame(&model, amodel, b->ent, (short *) ((qbyte *) model.header + mesh->index), tex_w, tex_h, b->mesh[0]);
|
||||
|
|
|
@ -46,8 +46,6 @@ texture_t r_notexture_mip_real;
|
|||
texture_t *r_notexture_mip = &r_notexture_mip_real;
|
||||
#endif
|
||||
|
||||
qboolean isnotmap = true; //used to not warp ammo models.
|
||||
|
||||
void CM_Init(void);
|
||||
void CM_Shutdown(void);
|
||||
|
||||
|
@ -1258,7 +1256,7 @@ static const char *Mod_RemapBuggyTexture(const char *name, const qbyte *data, un
|
|||
}
|
||||
|
||||
|
||||
void Mod_FinishTexture(texture_t *tx, const char *loadname)
|
||||
void Mod_FinishTexture(texture_t *tx, const char *loadname, qboolean safetoloadfromwads)
|
||||
{
|
||||
#ifndef SERVERONLY
|
||||
extern cvar_t gl_shadeq1_name;
|
||||
|
@ -1267,34 +1265,45 @@ void Mod_FinishTexture(texture_t *tx, const char *loadname)
|
|||
const char *origname = NULL;
|
||||
const char *shadername = tx->name;
|
||||
|
||||
|
||||
/*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
|
||||
if (!safetoloadfromwads)
|
||||
{
|
||||
//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);
|
||||
if (shadername)
|
||||
origname = tx->name;
|
||||
else
|
||||
shadername = tx->name;
|
||||
|
||||
//find the *
|
||||
if (!*gl_shadeq1_name.string || !strcmp(gl_shadeq1_name.string, "*"))
|
||||
;
|
||||
else if (!(star = strchr(gl_shadeq1_name.string, '*')) || (strlen(gl_shadeq1_name.string)+strlen(tx->name)+1>=sizeof(altname))) //it's got to fit.
|
||||
shadername = gl_shadeq1_name.string;
|
||||
/*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
|
||||
{
|
||||
strncpy(altname, gl_shadeq1_name.string, star-gl_shadeq1_name.string); //copy the left
|
||||
altname[star-gl_shadeq1_name.string] = '\0';
|
||||
strcat(altname, shadername); //insert the *
|
||||
strcat(altname, star+1); //add any final text.
|
||||
shadername = altname;
|
||||
//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);
|
||||
if (shadername)
|
||||
origname = tx->name;
|
||||
else
|
||||
shadername = tx->name;
|
||||
|
||||
//find the *
|
||||
if (!*gl_shadeq1_name.string || !strcmp(gl_shadeq1_name.string, "*"))
|
||||
;
|
||||
else if (!(star = strchr(gl_shadeq1_name.string, '*')) || (strlen(gl_shadeq1_name.string)+strlen(tx->name)+1>=sizeof(altname))) //it's got to fit.
|
||||
shadername = gl_shadeq1_name.string;
|
||||
else
|
||||
{
|
||||
strncpy(altname, gl_shadeq1_name.string, star-gl_shadeq1_name.string); //copy the left
|
||||
altname[star-gl_shadeq1_name.string] = '\0';
|
||||
strcat(altname, shadername); //insert the *
|
||||
strcat(altname, star+1); //add any final text.
|
||||
shadername = altname;
|
||||
}
|
||||
|
||||
tx->shader = R_RegisterCustom (shadername, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
|
||||
}
|
||||
|
||||
tx->shader = R_RegisterCustom (shadername, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
|
||||
if (!tx->mips[0] && !safetoloadfromwads)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{ //already loaded. don't waste time / crash (this will be a dead pointer).
|
||||
if (tx->mips[0])
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp(tx->name, "sky", 3))
|
||||
|
@ -1559,10 +1568,10 @@ void Mod_NowLoadExternal(model_t *loadmodel)
|
|||
if (!tx) //e1m2, this happens
|
||||
continue;
|
||||
|
||||
if (tx->shader)
|
||||
if (tx->mips[0])
|
||||
continue;
|
||||
|
||||
Mod_FinishTexture(tx, loadname);
|
||||
Mod_FinishTexture(tx, loadname, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1661,11 +1670,12 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
|
|||
if (!litdata && r_loadlits.value)
|
||||
{
|
||||
char *litnames[] = {
|
||||
"maps/%s.lit2",
|
||||
"maps/%s.lit",
|
||||
"%s.lit2",
|
||||
"%s.lit",
|
||||
"lits/%s.lit2",
|
||||
"lits/%s.lit"
|
||||
};
|
||||
char litbasep[MAX_QPATH];
|
||||
char litbase[MAX_QPATH];
|
||||
int depth;
|
||||
int bestdepth = 0x7fffffff;
|
||||
|
@ -1675,10 +1685,14 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
|
|||
size_t litsize;
|
||||
qboolean inhibitvalidation = false;
|
||||
|
||||
COM_StripExtension(loadmodel->name, litbase, sizeof(litbase));
|
||||
COM_StripExtension(loadmodel->name, litbasep, sizeof(litbasep));
|
||||
COM_FileBase(loadmodel->name, litbase, sizeof(litbase));
|
||||
for (i = 0; i < sizeof(litnames)/sizeof(litnames[0]); i++)
|
||||
{
|
||||
Q_snprintfz(litname, sizeof(litname), litnames[i], litbase);
|
||||
if (strchr(litnames[i], '/'))
|
||||
Q_snprintfz(litname, sizeof(litname), litnames[i], litbase);
|
||||
else
|
||||
Q_snprintfz(litname, sizeof(litname), litnames[i], litbasep);
|
||||
depth = COM_FDepthFile(litname, false);
|
||||
if (depth < bestdepth)
|
||||
{
|
||||
|
@ -1688,7 +1702,10 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
|
|||
}
|
||||
if (best >= 0)
|
||||
{
|
||||
Q_snprintfz(litname, sizeof(litname), litnames[best], litbase);
|
||||
if (strchr(litnames[best], '/'))
|
||||
Q_snprintfz(litname, sizeof(litname), litnames[best], litbase);
|
||||
else
|
||||
Q_snprintfz(litname, sizeof(litname), litnames[best], litbasep);
|
||||
litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize);
|
||||
}
|
||||
else
|
||||
|
@ -2179,8 +2196,7 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
|||
Mod_LoadSubmodels
|
||||
=================
|
||||
*/
|
||||
static qboolean hexen2map;
|
||||
qboolean Mod_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
||||
qboolean Mod_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean *hexen2map)
|
||||
{
|
||||
dq1model_t *inq;
|
||||
dh2model_t *inh;
|
||||
|
@ -2193,7 +2209,7 @@ qboolean Mod_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
|||
inh = (void *)(mod_base + l->fileofs);
|
||||
if (!inq->numfaces)
|
||||
{
|
||||
hexen2map = true;
|
||||
*hexen2map = true;
|
||||
if (l->filelen % sizeof(*inh))
|
||||
{
|
||||
Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name);
|
||||
|
@ -2231,7 +2247,7 @@ qboolean Mod_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
|||
}
|
||||
else
|
||||
{
|
||||
hexen2map = false;
|
||||
*hexen2map = false;
|
||||
if (l->filelen % sizeof(*inq))
|
||||
{
|
||||
Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name);
|
||||
|
@ -3204,7 +3220,7 @@ static void Mod_Batches_AllocLightmaps(model_t *mod)
|
|||
}
|
||||
samps /= 4;
|
||||
samps = sqrt(samps);
|
||||
if (j > 128 || !r_dynamic.ival)
|
||||
if (j > 128 || r_dynamic.ival <= 0)
|
||||
samps *= 2;
|
||||
mod->lightmaps.width = bound(j, samps, LMBLOCK_SIZE_MAX);
|
||||
mod->lightmaps.height = bound(j, samps, LMBLOCK_SIZE_MAX);
|
||||
|
@ -3500,7 +3516,7 @@ static qboolean Mod_LoadNodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, i
|
|||
Mod_LoadLeafs
|
||||
=================
|
||||
*/
|
||||
static qboolean Mod_LoadLeafs (model_t *loadmodel, qbyte *mod_base, lump_t *l, int lm, qbyte *ptr, size_t len)
|
||||
static qboolean Mod_LoadLeafs (model_t *loadmodel, qbyte *mod_base, lump_t *l, int lm, qboolean isnotmap, qbyte *ptr, size_t len)
|
||||
{
|
||||
mleaf_t *out;
|
||||
int i, j, count, p;
|
||||
|
@ -3784,7 +3800,7 @@ void Mod_LoadCrouchHull(model_t *loadmodel)
|
|||
Mod_LoadClipnodes
|
||||
=================
|
||||
*/
|
||||
qboolean Mod_LoadClipnodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean lm)
|
||||
qboolean Mod_LoadClipnodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean lm, qboolean hexen2map)
|
||||
{
|
||||
dsclipnode_t *ins;
|
||||
dlclipnode_t *inl;
|
||||
|
@ -4443,7 +4459,7 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b)
|
|||
if (!strncmp(loadname, "b_", 2))
|
||||
Q_strncpyz(loadname, "bmodels", sizeof(loadname));
|
||||
for(a = 0; a < mod->numtextures; a++)
|
||||
Mod_FinishTexture(mod->textures[a], loadname);
|
||||
Mod_FinishTexture(mod->textures[a], loadname, false);
|
||||
}
|
||||
}
|
||||
Mod_Batches_Build(mod, data);
|
||||
|
@ -4483,7 +4499,7 @@ static void Mod_FindVisPatch(struct vispatch_s *patch, model_t *mod, size_t leaf
|
|||
|
||||
//ignore the patch file if its in a different gamedir.
|
||||
//this file format sucks too much for other verification.
|
||||
if (FS_FLocateFile(mod->name,FSLFRT_DEPTH_OSONLY, NULL) != FS_FLocateFile(patchname,FSLFRT_DEPTH_OSONLY, NULL))
|
||||
if (FS_FLocateFile(mod->name,FSLF_DEPTH_EXPLICIT, NULL) != FS_FLocateFile(patchname,FSLF_DEPTH_EXPLICIT, NULL))
|
||||
return;
|
||||
|
||||
patch->filelen = FS_LoadFile(patchname, &patch->fileptr);
|
||||
|
@ -4547,6 +4563,8 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
|
|||
int longm = false;
|
||||
char loadname[32];
|
||||
qbyte *mod_base = buffer;
|
||||
qboolean hexen2map = false;
|
||||
qboolean isnotmap;
|
||||
#if (defined(ODE_STATIC) || defined(ODE_DYNAMIC))
|
||||
qboolean ode = true;
|
||||
#else
|
||||
|
@ -4662,7 +4680,7 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
|
|||
noerrors = noerrors && Mod_LoadTextures (mod, mod_base, &header->lumps[LUMP_TEXTURES]);
|
||||
}
|
||||
TRACE(("Loading Submodels\n"));
|
||||
noerrors = noerrors && Mod_LoadSubmodels (mod, mod_base, &header->lumps[LUMP_MODELS]);
|
||||
noerrors = noerrors && Mod_LoadSubmodels (mod, mod_base, &header->lumps[LUMP_MODELS], &hexen2map);
|
||||
if (noerrors)
|
||||
{
|
||||
TRACE(("Loading CH\n"));
|
||||
|
@ -4689,11 +4707,11 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
|
|||
TRACE(("Loading Vis\n"));
|
||||
Mod_LoadVisibility (mod, mod_base, &header->lumps[LUMP_VISIBILITY], vispatch.visptr, vispatch.vislen);
|
||||
}
|
||||
noerrors = noerrors && Mod_LoadLeafs (mod, mod_base, &header->lumps[LUMP_LEAFS], longm, vispatch.leafptr, vispatch.leaflen);
|
||||
noerrors = noerrors && Mod_LoadLeafs (mod, mod_base, &header->lumps[LUMP_LEAFS], longm, isnotmap, vispatch.leafptr, vispatch.leaflen);
|
||||
TRACE(("Loading Nodes\n"));
|
||||
noerrors = noerrors && Mod_LoadNodes (mod, mod_base, &header->lumps[LUMP_NODES], longm);
|
||||
TRACE(("Loading Clipnodes\n"));
|
||||
noerrors = noerrors && Mod_LoadClipnodes (mod, mod_base, &header->lumps[LUMP_CLIPNODES], longm);
|
||||
noerrors = noerrors && Mod_LoadClipnodes (mod, mod_base, &header->lumps[LUMP_CLIPNODES], longm, hexen2map);
|
||||
if (noerrors)
|
||||
{
|
||||
TRACE(("Loading hull 0\n"));
|
||||
|
|
|
@ -138,7 +138,11 @@ typedef struct batch_s
|
|||
/*caller-use, not interpreted by backend*/
|
||||
union
|
||||
{
|
||||
unsigned int shadowbatch; //a unique index to accelerate shadowmesh generation (dlights, yay!)
|
||||
struct
|
||||
{
|
||||
unsigned int shadowbatch; //a unique index to accelerate shadowmesh generation (dlights, yay!)
|
||||
unsigned int ebobatch; //
|
||||
};
|
||||
struct
|
||||
{
|
||||
unsigned int surf_first;
|
||||
|
@ -952,6 +956,7 @@ typedef struct model_s
|
|||
vbo_t *vbos;
|
||||
void *terrain;
|
||||
batch_t *batches[SHADER_SORT_COUNT];
|
||||
unsigned int numbatches;
|
||||
struct
|
||||
{
|
||||
int first; //once built...
|
||||
|
|
|
@ -192,6 +192,7 @@ index_t flashblend_indexes[FLASHBLEND_VERTS*3];
|
|||
index_t flashblend_fsindexes[6] = {0, 1, 2, 0, 2, 3};
|
||||
mesh_t flashblend_mesh;
|
||||
mesh_t flashblend_fsmesh;
|
||||
shader_t *occluded_shader;
|
||||
shader_t *flashblend_shader;
|
||||
shader_t *lpplight_shader;
|
||||
|
||||
|
@ -264,6 +265,15 @@ void R_InitFlashblends(void)
|
|||
"}\n"
|
||||
"}\n"
|
||||
);
|
||||
occluded_shader = R_RegisterShader("flashblend_occlusiontest", SUF_NONE,
|
||||
"{\n"
|
||||
"program defaultadditivesprite\n"
|
||||
"{\n"
|
||||
"maskcolor\n"
|
||||
"maskalpha\n"
|
||||
"}\n"
|
||||
"}\n"
|
||||
);
|
||||
lpplight_shader = NULL;
|
||||
}
|
||||
|
||||
|
@ -401,16 +411,97 @@ void R_RenderDlights (void)
|
|||
/*coronas use depth testing to compute visibility*/
|
||||
if (coronastyle)
|
||||
{
|
||||
extern cvar_t temp1;
|
||||
if (r_coronas_occlusion.ival)
|
||||
int method;
|
||||
if (!*r_coronas_occlusion.string)
|
||||
method = 4;
|
||||
else
|
||||
method = r_coronas_occlusion.ival;
|
||||
if (method == 3 && qrenderer != QR_OPENGL)
|
||||
method = 1;
|
||||
if (method == 4 && (qrenderer != QR_OPENGL || !qglGenQueriesARB))
|
||||
method = 1;
|
||||
|
||||
switch(method)
|
||||
{
|
||||
case 2:
|
||||
if (TraceLineR(r_refdef.vieworg, l->origin, waste1, waste2))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
default:
|
||||
case 1:
|
||||
if (TraceLineN(r_refdef.vieworg, l->origin, waste1, waste2))
|
||||
continue;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
#ifdef GLQUAKE
|
||||
case 3:
|
||||
{
|
||||
float depth;
|
||||
vec3_t out;
|
||||
float v[4], tempv[4];
|
||||
float mvp[16];
|
||||
|
||||
v[0] = l->origin[0];
|
||||
v[1] = l->origin[1];
|
||||
v[2] = l->origin[2];
|
||||
v[3] = 1;
|
||||
|
||||
Matrix4_Multiply(r_refdef.m_projection, r_refdef.m_view, mvp);
|
||||
Matrix4x4_CM_Transform4(mvp, v, tempv);
|
||||
|
||||
tempv[0] /= tempv[3];
|
||||
tempv[1] /= tempv[3];
|
||||
tempv[2] /= tempv[3];
|
||||
|
||||
out[0] = (1+tempv[0])/2;
|
||||
out[1] = (1+tempv[1])/2;
|
||||
out[2] = (1+tempv[2])/2;
|
||||
|
||||
out[0] = out[0]*r_refdef.pxrect.width + r_refdef.pxrect.x;
|
||||
out[1] = out[1]*r_refdef.pxrect.height + r_refdef.pxrect.y;
|
||||
if (tempv[3] < 0)
|
||||
out[2] *= -1;
|
||||
|
||||
if (out[2] < 0)
|
||||
continue;
|
||||
|
||||
//FIXME: in terms of performance, mixing reads+draws is BAD BAD BAD. SERIOUSLY BAD
|
||||
qglReadPixels(out[0], out[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
|
||||
if (depth < out[2])
|
||||
continue;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
GLuint res;
|
||||
qboolean requery = true;
|
||||
if (l->coronaocclusionquery)
|
||||
{
|
||||
qglGetQueryObjectuivARB(l->coronaocclusionquery, GL_QUERY_RESULT_AVAILABLE_ARB, &res);
|
||||
if (res)
|
||||
qglGetQueryObjectuivARB(l->coronaocclusionquery, GL_QUERY_RESULT_ARB, &l->coronaocclusionresult);
|
||||
else if (!l->coronaocclusionresult)
|
||||
continue; //query still running, nor currently visible.
|
||||
else
|
||||
requery = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
qglGenQueriesARB(1, &l->coronaocclusionquery);
|
||||
}
|
||||
|
||||
if (requery)
|
||||
{
|
||||
qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, l->coronaocclusionquery);
|
||||
R_BuildDlightMesh (l, intensity*10, 0.01, coronastyle);
|
||||
BE_DrawMesh_Single(occluded_shader, &flashblend_mesh, NULL, beflags);
|
||||
qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
|
||||
}
|
||||
|
||||
if (!l->coronaocclusionresult)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -530,7 +621,7 @@ void R_PushDlights (void)
|
|||
return;
|
||||
#endif
|
||||
|
||||
if (!r_dynamic.ival || !cl.worldmodel)
|
||||
if (r_dynamic.ival <= 0|| !cl.worldmodel)
|
||||
return;
|
||||
|
||||
if (!cl.worldmodel->nodes)
|
||||
|
|
|
@ -329,6 +329,7 @@ void GLBE_GenBatchVBOs(vbo_t **vbochain, batch_t *firstbatch, batch_t *stopbatch
|
|||
BZ_Free(vbo->vertdata);
|
||||
vbo->vertdata = NULL;
|
||||
}
|
||||
vbo->vertcount = vcount;
|
||||
|
||||
vbo->next = *vbochain;
|
||||
*vbochain = vbo;
|
||||
|
@ -506,6 +507,7 @@ void GLBE_GenBrushModelVBO(model_t *mod)
|
|||
BZ_Free(vbo->vertdata);
|
||||
vbo->vertdata = NULL;
|
||||
}
|
||||
vbo->vertcount = vcount;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -524,8 +526,8 @@ void GLBE_UploadAllLightmaps(void)
|
|||
lm = lightmap[i];
|
||||
lm->rectchange.l = lm->width;
|
||||
lm->rectchange.t = lm->height;
|
||||
lm->rectchange.w = 0;
|
||||
lm->rectchange.h = 0;
|
||||
lm->rectchange.r = 0;
|
||||
lm->rectchange.b = 0;
|
||||
if (!lm->modified)
|
||||
continue;
|
||||
lm->modified = false;
|
||||
|
|
|
@ -212,11 +212,11 @@ void GLSCR_UpdateScreen (void)
|
|||
Media_RecordFrame();
|
||||
#endif
|
||||
|
||||
RSpeedShow();
|
||||
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
||||
RSpeedEnd(RSPEED_TOTALREFRESH);
|
||||
RSpeedShow();
|
||||
|
||||
RSpeedRemark();
|
||||
VID_SwapBuffers();
|
||||
|
|
|
@ -4597,6 +4597,9 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, cons
|
|||
imageflags = (basefmt==TF_SOLID8 || basefmt == TF_MIP4_SOLID8)?IF_NOALPHA:0;
|
||||
imageflags |= IF_MIPCAP;
|
||||
|
||||
if (basefmt == TF_MIP4_SOLID8 && palette && palette != host_basepal)
|
||||
basefmt = TF_MIP4_8PAL24;
|
||||
|
||||
COM_StripExtension(imagename, imagename, sizeof(imagename));
|
||||
|
||||
aframes = max(1, shader->numdefaulttextures);
|
||||
|
@ -4710,8 +4713,8 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, cons
|
|||
if (!TEXVALID(tex->fullbright))
|
||||
{
|
||||
int s=-1;
|
||||
if (mipdata[0])
|
||||
for(s = width*height; s-->0; )
|
||||
if (mipdata[0] && (!palette || palette == host_basepal))
|
||||
for(s = width*height-1; s>=0; s--)
|
||||
{
|
||||
if (mipdata[0][s] >= 256-vid.fullbright)
|
||||
break;
|
||||
|
|
|
@ -3144,8 +3144,6 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, vec3_t axis[3],
|
|||
Sh_DrawEntLighting(dl, colour);
|
||||
}
|
||||
|
||||
void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop);
|
||||
|
||||
void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
|
||||
{
|
||||
#ifdef GLQUAKE
|
||||
|
@ -3221,7 +3219,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
|
|||
|
||||
BE_SelectMode(BEM_CREPUSCULAR);
|
||||
BE_SelectDLight(dl, colours, dl->axis, LSHADER_STANDARD);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_BLEND);
|
||||
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_PORTAL, SHADER_SORT_BLEND);
|
||||
|
||||
GLBE_FBO_Pop(oldfbo);
|
||||
|
||||
|
|
|
@ -62,6 +62,15 @@ void (APIENTRY *qglGetVertexAttribPointerv) (GLuint index, GLenum pname, GLvoid*
|
|||
BINDTEXFUNCPTR qglBindTexture;
|
||||
|
||||
|
||||
void (APIENTRY *qglGenQueriesARB)(GLsizei n, GLuint *ids);
|
||||
void (APIENTRY *qglDeleteQueriesARB)(GLsizei n, const GLuint *ids);
|
||||
//extern GLboolean (APIENTRY *qglIsQueryARB)(GLuint id);
|
||||
void (APIENTRY *qglBeginQueryARB)(GLenum target, GLuint id);
|
||||
void (APIENTRY *qglEndQueryARB)(GLenum target);
|
||||
//extern void (APIENTRY *qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
|
||||
//extern void (APIENTRY *qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params);
|
||||
void (APIENTRY *qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params);
|
||||
|
||||
/*glslang - arb_shader_objects
|
||||
gl core uses different names/distinctions from the extension
|
||||
*/
|
||||
|
@ -1144,6 +1153,31 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
|
|||
}
|
||||
#endif
|
||||
|
||||
if (!gl_config.gles && gl_config.glversion >= 1.5)
|
||||
{
|
||||
qglGenQueriesARB = (void *)getglext("glGenQueries");
|
||||
qglDeleteQueriesARB = (void *)getglext("glDeleteQueries");
|
||||
qglBeginQueryARB = (void *)getglext("glBeginQuery");
|
||||
qglEndQueryARB = (void *)getglext("glEndQuery");
|
||||
qglGetQueryObjectuivARB = (void *)getglext("glGetQueryObjectuiv");
|
||||
}
|
||||
else if (GL_CheckExtension("GL_ARB_occlusion_query"))
|
||||
{
|
||||
qglGenQueriesARB = (void *)getglext("glGenQueriesARB");
|
||||
qglDeleteQueriesARB = (void *)getglext("glDeleteQueriesARB");
|
||||
qglBeginQueryARB = (void *)getglext("glBeginQueryARB");
|
||||
qglEndQueryARB = (void *)getglext("glEndQueryARB");
|
||||
qglGetQueryObjectuivARB = (void *)getglext("glGetQueryObjectuivARB");
|
||||
}
|
||||
else
|
||||
{
|
||||
qglGenQueriesARB = NULL;
|
||||
qglDeleteQueriesARB = NULL;
|
||||
qglBeginQueryARB = NULL;
|
||||
qglEndQueryARB = NULL;
|
||||
qglGetQueryObjectuivARB = NULL;
|
||||
}
|
||||
|
||||
if (!gl_config.gles && gl_config_nofixedfunc)
|
||||
qglDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
@ -1822,7 +1856,7 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char *
|
|||
length[strings] = strlen(prstrings[strings]);
|
||||
strings++;
|
||||
}
|
||||
if (ver >= 140)
|
||||
if (ver >= 130) //gl3+ deprecated the varying keyword for geometry shaders to work properly
|
||||
{
|
||||
prstrings[strings] =
|
||||
"#define varying in\n"
|
||||
|
@ -1862,7 +1896,7 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char *
|
|||
length[strings] = strlen(prstrings[strings]);
|
||||
strings++;
|
||||
}
|
||||
if (ver >= 140)
|
||||
if (ver >= 130)
|
||||
{
|
||||
prstrings[strings] =
|
||||
"#define attribute in\n"
|
||||
|
@ -1871,7 +1905,7 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char *
|
|||
length[strings] = strlen(prstrings[strings]);
|
||||
strings++;
|
||||
}
|
||||
if (gl_config.nofixedfunc || ver >= 140)
|
||||
if (gl_config.nofixedfunc || ver >= 130)
|
||||
{
|
||||
prstrings[strings] =
|
||||
"attribute vec3 v_position1;\n"
|
||||
|
|
|
@ -759,7 +759,7 @@ void R_InitSky (shader_t *shader, const char *skyname, qbyte *src, unsigned int
|
|||
unsigned int stride = width;
|
||||
width /= 2;
|
||||
|
||||
if (width < 1 || height < 1 || stride != width*2)
|
||||
if (width < 1 || height < 1 || stride != width*2 || !src)
|
||||
return;
|
||||
|
||||
if (width*height > countof(trans))
|
||||
|
|
|
@ -693,6 +693,15 @@ extern GLenum (APIENTRY *qglCheckFramebufferStatusEXT)(GLenum target);
|
|||
extern void (APIENTRY *qglGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint * params);
|
||||
|
||||
|
||||
extern void (APIENTRY *qglGenQueriesARB)(GLsizei n, GLuint *ids);
|
||||
extern void (APIENTRY *qglDeleteQueriesARB)(GLsizei n, const GLuint *ids);
|
||||
//extern GLboolean (APIENTRY *qglIsQueryARB)(GLuint id);
|
||||
extern void (APIENTRY *qglBeginQueryARB)(GLenum target, GLuint id);
|
||||
extern void (APIENTRY *qglEndQueryARB)(GLenum target);
|
||||
//extern void (APIENTRY *qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
|
||||
//extern void (APIENTRY *qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params);
|
||||
extern void (APIENTRY *qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params);
|
||||
|
||||
//glslang - arb_shader_objects
|
||||
extern FTEPFNGLCREATEPROGRAMOBJECTARBPROC qglCreateProgramObjectARB;
|
||||
extern FTEPFNGLDELETEOBJECTARBPROC qglDeleteProgramObject_;
|
||||
|
|
|
@ -764,4 +764,14 @@ typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
|
|||
#define GL_RGBA32F_ARB 0x8814
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef GL_SAMPLES_PASSED_ARB
|
||||
#define GL_SAMPLES_PASSED_ARB 0x8914
|
||||
//#define GL_QUERY_COUNTER_BITS_ARB 0x8864
|
||||
//#define GL_CURRENT_QUERY_ARB 0x8865
|
||||
#define GL_QUERY_RESULT_ARB 0x8866
|
||||
#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -558,8 +558,6 @@ static void LightCalcPoints (llightinfo_t *l, float lmscale)
|
|||
VectorSubtract (facemid, surf, move);
|
||||
VectorNormalize (move);
|
||||
VectorMA (surf, 8, move, surf);
|
||||
|
||||
P_RunParticleEffectType(surf, NULL, 1, pt_wizspike);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ typedef struct
|
|||
int unknown7[2];
|
||||
float unknown[4];
|
||||
int unknown8;
|
||||
int seqindex;
|
||||
unsigned int seqindex;
|
||||
int unknown9[4];
|
||||
} hlmdl_sequencelist_t;
|
||||
|
||||
|
@ -193,10 +193,17 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
char name[96]; /* should be split label[32] and name[64] */
|
||||
void * cache;
|
||||
unsigned int cache;
|
||||
int data;
|
||||
} hlmdl_sequencedata_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int magic; //IDSQ
|
||||
int version; //10
|
||||
char name[64];
|
||||
int unk1;
|
||||
} hlmdl_sequencefile_t;
|
||||
/*
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
halflife model internal structure
|
||||
|
@ -209,21 +216,27 @@ typedef struct
|
|||
|
||||
/* Static pointers */
|
||||
hlmdl_header_t *header;
|
||||
hlmdl_header_t *texheader;
|
||||
hlmdl_tex_t *textures;
|
||||
hlmdl_bone_t *bones;
|
||||
hlmdl_bonecontroller_t *bonectls;
|
||||
shader_t **shaders;
|
||||
hlmdl_bonecontroller_t *bonectls;
|
||||
struct hlmodelshaders_s *shaders;
|
||||
hlmdl_sequencefile_t **animcache;
|
||||
zonegroup_t *memgroup;
|
||||
} hlmodel_t;
|
||||
|
||||
#define MAX_ANIM_GROUPS 16 //submodel files containing anim data.
|
||||
typedef struct //this is stored as the cache. an hlmodel_t is generated when drawing
|
||||
{
|
||||
int header;
|
||||
int texheader;
|
||||
int textures;
|
||||
int bones;
|
||||
int bonectls;
|
||||
int shaders;
|
||||
hlmdl_header_t *header;
|
||||
hlmdl_bone_t *bones;
|
||||
hlmdl_bonecontroller_t *bonectls;
|
||||
hlmdl_sequencefile_t *animcache[MAX_ANIM_GROUPS];
|
||||
struct hlmodelshaders_s
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
texnums_t defaulttex;
|
||||
shader_t *shader;
|
||||
int w, h;
|
||||
} *shaders;
|
||||
short *skins;
|
||||
int numskins;
|
||||
} hlmodelcache_t;
|
||||
|
|
|
@ -717,12 +717,12 @@ batch_t *GLBE_GetTempBatch(void);
|
|||
void GLBE_GenBrushModelVBO(model_t *mod);
|
||||
void GLBE_ClearVBO(vbo_t *vbo);
|
||||
void GLBE_UploadAllLightmaps(void);
|
||||
void GLBE_DrawWorld (qboolean drawworld, qbyte *vis);
|
||||
void GLBE_DrawWorld (batch_t **worldbatches, qbyte *vis);
|
||||
qboolean GLBE_LightCullModel(vec3_t org, model_t *model);
|
||||
void GLBE_SelectEntity(entity_t *ent);
|
||||
qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode);
|
||||
void GLBE_Scissor(srect_t *rect);
|
||||
void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop);
|
||||
void GLBE_SubmitMeshes (batch_t **worldbatches, int start, int stop);
|
||||
//void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth);
|
||||
void GLBE_RenderToTextureUpdate2d(qboolean destchanged);
|
||||
void GLBE_VBO_Begin(vbobctx_t *ctx, size_t maxsize);
|
||||
|
@ -780,9 +780,9 @@ qboolean D3D11Shader_Init(unsigned int featurelevel);
|
|||
void D3D11BE_Reset(qboolean before);
|
||||
void D3D11BE_SetupViewCBuffer(void);
|
||||
void D3D11_UploadLightmap(lightmapinfo_t *lm);
|
||||
void D3D11BE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize);
|
||||
void D3D11BE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray);
|
||||
void D3D11BE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray);
|
||||
void D3D11BE_VBO_Begin(vbobctx_t *ctx, size_t maxsize);
|
||||
void D3D11BE_VBO_Data(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray);
|
||||
void D3D11BE_VBO_Finish(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earray);
|
||||
void D3D11BE_VBO_Destroy(vboarray_t *vearray);
|
||||
void D3D11BE_Scissor(srect_t *rect);
|
||||
|
||||
|
|
|
@ -307,7 +307,8 @@ void HTTP_RunExisting (void)
|
|||
ammount = recv(cl->datasock, cl->inbuffer+cl->inbufferused, ammount, 0);
|
||||
if (ammount < 0)
|
||||
{
|
||||
if (neterrno() != NET_EWOULDBLOCK) //they closed on us. Assume end.
|
||||
int e = neterrno();
|
||||
if (e != NET_EWOULDBLOCK) //they closed on us. Assume end.
|
||||
{
|
||||
cl->closereason = "recv error";
|
||||
}
|
||||
|
|
|
@ -1651,6 +1651,14 @@ char *ED_WriteEdict(progfuncs_t *progfuncs, edictrun_t *ed, char *buf, int *bufo
|
|||
#undef AddS
|
||||
}
|
||||
|
||||
//just a simple helper that makes sure the s_name+s_file values are actually valid. some qccs generate really dodgy values intended to crash decompilers, but also crash debuggers too.
|
||||
static char *PR_StaticString(progfuncs_t *progfuncs, string_t thestring)
|
||||
{
|
||||
if (thestring <= 0 || thestring >= progfuncs->funcs.stringtablesize)
|
||||
return "???";
|
||||
return thestring + progfuncs->funcs.stringtable;
|
||||
}
|
||||
|
||||
char *PR_SaveCallStack (progfuncs_t *progfuncs, char *buf, int *bufofs, int bufmax)
|
||||
{
|
||||
#define AddS(str) PR_Cat(buf, str, bufofs, bufmax)
|
||||
|
@ -1691,9 +1699,9 @@ char *PR_SaveCallStack (progfuncs_t *progfuncs, char *buf, int *bufofs, int bufm
|
|||
AddS (buffer);
|
||||
}
|
||||
if (!f->s_file)
|
||||
sprintf(buffer, "\t\"%i:%s\"\n", progs, f->s_name+progfuncs->funcs.stringtable);
|
||||
sprintf(buffer, "\t\"%i:%s\"\n", progs, PR_StaticString(progfuncs, f->s_name));
|
||||
else
|
||||
sprintf(buffer, "\t\"%i:%s\" //%s\n", progs, f->s_name+progfuncs->funcs.stringtable, f->s_file+progfuncs->funcs.stringtable);
|
||||
sprintf(buffer, "\t\"%i:%s\" //%s\n", progs, PR_StaticString(progfuncs, f->s_name), PR_StaticString(progfuncs, f->s_file));
|
||||
AddS (buffer);
|
||||
|
||||
AddS ("\t{\n");
|
||||
|
@ -1707,10 +1715,10 @@ char *PR_SaveCallStack (progfuncs_t *progfuncs, char *buf, int *bufofs, int bufm
|
|||
{
|
||||
if (local->type == ev_entity)
|
||||
{
|
||||
sprintf(buffer, "\t\t\"%s\" \"entity %i\"\n", local->s_name+progfuncs->funcs.stringtable, ((eval_t*)(globalbase - f->locals+arg))->edict);
|
||||
sprintf(buffer, "\t\t\"%s\" \"entity %i\"\n", PR_StaticString(progfuncs, local->s_name), ((eval_t*)(globalbase - f->locals+arg))->edict);
|
||||
}
|
||||
else
|
||||
sprintf(buffer, "\t\t\"%s\"\t\"%s\"\n", local->s_name+progfuncs->funcs.stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg), false));
|
||||
sprintf(buffer, "\t\t\"%s\"\t\"%s\"\n", PR_StaticString(progfuncs, local->s_name), PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg), false));
|
||||
|
||||
if (local->type == ev_vector)
|
||||
arg+=2;
|
||||
|
|
|
@ -1072,17 +1072,17 @@ void PR_Compile_f(void)
|
|||
argv[4] = Cmd_Argv(1);
|
||||
argc = 5;
|
||||
}
|
||||
if (!FS_FLocateFile(va("%s/%s", argv[2], argv[4]), FSLFRT_IFFOUND, NULL))
|
||||
if (!FS_FLocateFile(va("%s/%s", argv[2], argv[4]), FSLF_IFFOUND, NULL))
|
||||
{
|
||||
//try the qc path
|
||||
argv[2] = "qc";
|
||||
}
|
||||
if (!FS_FLocateFile(va("%s/%s", argv[2], argv[4]), FSLFRT_IFFOUND, NULL))
|
||||
if (!FS_FLocateFile(va("%s/%s", argv[2], argv[4]), FSLF_IFFOUND, NULL))
|
||||
{
|
||||
//try the progs path (yeah... gah)
|
||||
argv[2] = "progs";
|
||||
}
|
||||
if (!FS_FLocateFile(va("%s/%s", argv[2], argv[4]), FSLFRT_IFFOUND, NULL))
|
||||
if (!FS_FLocateFile(va("%s/%s", argv[2], argv[4]), FSLF_IFFOUND, NULL))
|
||||
{
|
||||
//try the gamedir path
|
||||
argv[1] = argv[3];
|
||||
|
@ -3782,7 +3782,7 @@ static void QCBUILTIN PF_precache_file (pubprogfuncs_t *prinst, struct globalvar
|
|||
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
||||
|
||||
/*touch the file, so any packs will be referenced. this is fte-specific behaviour.*/
|
||||
FS_FLocateFile(s, FSLFRT_IFFOUND, NULL);
|
||||
FS_FLocateFile(s, FSLF_IFFOUND, NULL);
|
||||
}
|
||||
|
||||
int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
|
||||
|
@ -3802,7 +3802,7 @@ int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
|
|||
Q_strncpyz(sv.strings.sound_precache[i], s, sizeof(sv.strings.sound_precache[i]));
|
||||
|
||||
/*touch the file, so any packs will be referenced*/
|
||||
FS_FLocateFile(s, FSLFRT_IFFOUND, NULL);
|
||||
FS_FLocateFile(s, FSLF_IFFOUND, NULL);
|
||||
|
||||
if (sv.state != ss_loading)
|
||||
{
|
||||
|
@ -3868,7 +3868,7 @@ int PF_precache_model_Internal (pubprogfuncs_t *prinst, const char *s, qboolean
|
|||
else
|
||||
{
|
||||
/*touch the file, so any packs will be referenced*/
|
||||
FS_FLocateFile(s, FSLFRT_IFFOUND, NULL);
|
||||
FS_FLocateFile(s, FSLF_IFFOUND, NULL);
|
||||
}
|
||||
|
||||
if (sv.state != ss_loading)
|
||||
|
@ -11346,6 +11346,7 @@ void PR_DumpPlatform_f(void)
|
|||
|
||||
VFS_PRINTF(f, "#pragma warning error Q101 /*too many parms*/\n");
|
||||
VFS_PRINTF(f, "#pragma warning error Q105 /*too few parms*/\n");
|
||||
VFS_PRINTF(f, "#pragma warning error Q106 /*assignment to constant/lvalue*/\n");
|
||||
VFS_PRINTF(f, "#pragma warning error Q208 /*system crc unknown*/\n");
|
||||
VFS_PRINTF(f, "#pragma warning enable F301 /*non-utf-8 strings*/\n");
|
||||
VFS_PRINTF(f, "#pragma warning enable F302 /*uninitialised locals*/\n");
|
||||
|
|
|
@ -608,7 +608,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!FS_FLocateFile(name, FSLFRT_IFFOUND, &loc))
|
||||
if (!FS_FLocateFile(name, FSLF_IFFOUND, &loc))
|
||||
{
|
||||
Con_Printf("Couldn't find %s.\n", name);
|
||||
return false;
|
||||
|
@ -1493,7 +1493,7 @@ void SV_Loadgame_f (void)
|
|||
{
|
||||
flocation_t loc;
|
||||
char *name = va("saves/%s/game.gsv", savename);
|
||||
if (!FS_FLocateFile(name, FSLFRT_IFFOUND, &loc))
|
||||
if (!FS_FLocateFile(name, FSLF_IFFOUND, &loc))
|
||||
Con_Printf("Couldn't find %s.\n", name);
|
||||
else if (!*loc.rawname || loc.offset)
|
||||
Con_Printf("%s is inside a package and cannot be used by the quake2 gamecode.\n", name);
|
||||
|
|
|
@ -221,7 +221,10 @@ void MSV_MapCluster_f(void)
|
|||
|
||||
//child processes return 0 and fall through
|
||||
memset(&sv, 0, sizeof(sv));
|
||||
if (atoi(Cmd_Argv(1)))
|
||||
Q_strncpyz(sv.modelname, Cmd_Argv(1), sizeof(sv.modelname));
|
||||
if (!*sv.modelname)
|
||||
Q_strncpyz(sv.modelname, "start", sizeof(sv.modelname));
|
||||
if (atoi(Cmd_Argv(2)))
|
||||
{
|
||||
Con_Printf("Opening database \"%s\"\n", sqlparams[3]);
|
||||
sv.logindatabase = SQL_NewServer("sqlite", sqlparams);
|
||||
|
@ -626,7 +629,7 @@ void SSV_ReadFromControlServer(void)
|
|||
char *addr = MSG_ReadString();
|
||||
int i;
|
||||
|
||||
Con_Printf("%s: got tookplayer\n", sv.name);
|
||||
Con_Printf("%s: got tookplayer\n", sv.modelname);
|
||||
|
||||
for (i = 0; i < svs.allocated_client_slots; i++)
|
||||
{
|
||||
|
@ -640,19 +643,19 @@ void SSV_ReadFromControlServer(void)
|
|||
{
|
||||
if (!*addr)
|
||||
{
|
||||
Con_Printf("%s: tookplayer: failed\n", sv.name);
|
||||
Con_Printf("%s: tookplayer: failed\n", sv.modelname);
|
||||
Info_SetValueForStarKey(cl->userinfo, "*transfer", "", sizeof(cl->userinfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf("%s: tookplayer: do transfer\n", sv.name);
|
||||
Con_Printf("%s: tookplayer: do transfer\n", sv.modelname);
|
||||
// SV_StuffcmdToClient(cl, va("connect \"%s\"\n", addr));
|
||||
SV_StuffcmdToClient(cl, va("cl_transfer \"%s\"\n", addr));
|
||||
cl->redirect = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
Con_Printf("%s: tookplayer: invalid player.\n", sv.name);
|
||||
Con_Printf("%s: tookplayer: invalid player.\n", sv.modelname);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -723,7 +726,7 @@ void SSV_ReadFromControlServer(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
Con_Printf("%s: server full!\n", sv.name);
|
||||
Con_Printf("%s: server full!\n", sv.modelname);
|
||||
}
|
||||
|
||||
j = MSG_ReadByte();
|
||||
|
@ -838,7 +841,7 @@ void SSV_UpdateAddresses(void)
|
|||
send.cursize = 2;
|
||||
MSG_WriteByte(&send, ccmd_serveraddress);
|
||||
|
||||
MSG_WriteString(&send, sv.name);
|
||||
MSG_WriteString(&send, sv.modelname);
|
||||
for (i = 0; i < count; i++)
|
||||
MSG_WriteString(&send, NET_AdrToString(buf, sizeof(buf), &addr[i]));
|
||||
MSG_WriteByte(&send, 0);
|
||||
|
@ -971,7 +974,7 @@ qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serv
|
|||
pubsubserver_t *s = NULL;
|
||||
|
||||
if (!s)
|
||||
s = MSV_FindSubServerName(":start");
|
||||
s = MSV_FindSubServerName(va(":%s", sv.modelname));
|
||||
|
||||
if (!s || !MSV_AddressForServer(&serveraddr, clientaddr->type, s))
|
||||
SV_RejectMessage(SCP_QUAKEWORLD, "Unable to find lobby.\n");
|
||||
|
|
|
@ -739,7 +739,7 @@ void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
|
|||
if (bits & U_COLORMAP)
|
||||
MSG_WriteByte (msg, to->colormap);
|
||||
if (bits & U_SKIN)
|
||||
MSG_WriteByte (msg, to->skinnum);
|
||||
MSG_WriteByte (msg, to->skinnum&0xff);
|
||||
if (bits & U_EFFECTS)
|
||||
MSG_WriteByte (msg, to->effects&0x00ff);
|
||||
if (bits & U_ORIGIN1)
|
||||
|
@ -3647,7 +3647,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
|
|||
cameras = NULL;
|
||||
#ifdef HLSERVER
|
||||
else if (svs.gametype == GT_HALFLIFE)
|
||||
pvs = SVHL_Snapshot_SetupPVS(client, pvsbuffer, sizeof(pvsbuffer));
|
||||
SVHL_Snapshot_SetupPVS(client, cameras->pvs, sizeof(cameras->pvs));
|
||||
#endif
|
||||
else
|
||||
SV_Snapshot_SetupPVS(client, cameras);
|
||||
|
@ -3682,7 +3682,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
|
|||
{
|
||||
#ifdef HLSERVER
|
||||
if (svs.gametype == GT_HALFLIFE)
|
||||
SVHL_Snapshot_Build(client, pack, pvs, clent, ignorepvs);
|
||||
SVHL_Snapshot_Build(client, pack, cameras->pvs, clent, ignorepvs);
|
||||
else
|
||||
#endif
|
||||
SV_Snapshot_BuildQ1(client, pack, cameras, clent);
|
||||
|
|
|
@ -223,7 +223,7 @@ baseline will be transmitted
|
|||
|
||||
void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *client);
|
||||
|
||||
void SVNQ_CreateBaseline (void)
|
||||
void SVQ1_CreateBaseline (void)
|
||||
{
|
||||
edict_t *svent;
|
||||
int entnum;
|
||||
|
@ -1587,7 +1587,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
|
|||
// create a baseline for more efficient communications
|
||||
// SV_CreateBaseline ();
|
||||
if (svprogfuncs)
|
||||
SVNQ_CreateBaseline();
|
||||
SVQ1_CreateBaseline();
|
||||
#ifdef Q2SERVER
|
||||
SVQ2_BuildBaselines();
|
||||
#endif
|
||||
|
|
|
@ -1748,7 +1748,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
|
|||
|
||||
//some gamecode can't cope with some extensions for some reasons... and I'm too lazy to fix the code to cope.
|
||||
if (svs.gametype == GT_HALFLIFE)
|
||||
client->fteprotocolextensions2 &= ~PEXT2_REPLACEMENTDELTAS;
|
||||
client->fteprotocolextensions2 &= ~PEXT2_REPLACEMENTDELTAS; //baseline issues
|
||||
|
||||
//
|
||||
client->maxmodels = 256;
|
||||
|
@ -2593,6 +2593,7 @@ client_t *SVC_DirectConnect(void)
|
|||
Con_TPrintf ("%s:gamecode reject\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr));
|
||||
return NULL;
|
||||
}
|
||||
temp.hledict = newcl->hledict;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -5030,7 +5031,7 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
|
|||
cl->rate = ISNQCLIENT(cl)?10000:2500; //an nq client cannot cope with quakeworld's default rate, and typically doesn't have rate set either.
|
||||
|
||||
val = Info_ValueForKey (cl->userinfo, "dupe");
|
||||
cl->netchan.dupe = atoi(val);
|
||||
cl->netchan.dupe = bound(0, atoi(val), 5);
|
||||
|
||||
val = Info_ValueForKey (cl->userinfo, "drate");
|
||||
if (strlen(val))
|
||||
|
|
|
@ -2509,6 +2509,7 @@ qboolean SV_Physics (void)
|
|||
if (svs.gametype == GT_HALFLIFE)
|
||||
{
|
||||
SVHL_RunFrame();
|
||||
sv.world.physicstime += host_frametime;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1367,6 +1367,11 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
|
|||
client->nextservertimeupdate = sv.physicstime;
|
||||
*/
|
||||
|
||||
#ifdef HLSERVER
|
||||
if (svs.gametype == GT_HALFLIFE)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef NQPROT
|
||||
ent = client->edict;
|
||||
if (progstype != PROG_QW)
|
||||
|
|
|
@ -47,8 +47,8 @@ cvar_t sv_spectalk = SCVAR("sv_spectalk", "1");
|
|||
cvar_t sv_mapcheck = SCVAR("sv_mapcheck", "1");
|
||||
|
||||
cvar_t sv_fullredirect = CVARD("sv_fullredirect", "", "This is the ip:port to redirect players to when the server is full");
|
||||
cvar_t sv_antilag = CVARFD("sv_antilag", "1", CVAR_SERVERINFO, "Attempt to backdate impacts to compensate for lag. 0=completely off. 1=mod-controlled. 2=forced, which might break certain uses of traceline.");
|
||||
cvar_t sv_antilag_frac = CVARF("sv_antilag_frac", "1", CVAR_SERVERINFO);
|
||||
cvar_t sv_antilag = CVARFD("sv_antilag", "", CVAR_SERVERINFO, "Attempt to backdate impacts to compensate for lag. 0=completely off. 1=mod-controlled. 2=forced, which might break certain uses of traceline.");
|
||||
cvar_t sv_antilag_frac = CVARF("sv_antilag_frac", "", CVAR_SERVERINFO);
|
||||
#ifndef NEWSPEEDCHEATPROT
|
||||
cvar_t sv_cheatpc = CVARD("sv_cheatpc", "125", "If the client tried to claim more than this percentage of time within any speed-cheat period, the client will be deemed to have cheated.");
|
||||
cvar_t sv_cheatspeedchecktime = CVARD("sv_cheatspeedchecktime", "30", "The interval between each speed-cheat check.");
|
||||
|
@ -57,6 +57,9 @@ 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", "0", "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_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");
|
||||
|
||||
cvar_t sv_cmdlikercon = SCVAR("sv_cmdlikercon", "0"); //set to 1 to allow a password of username:password instead of the correct rcon password.
|
||||
cvar_t cmd_allowaccess = SCVAR("cmd_allowaccess", "0"); //set to 1 to allow cmd to execute console commands on the server.
|
||||
cvar_t cmd_gamecodelevel = SCVAR("cmd_gamecodelevel", STRINGIFY(RESTRICT_LOCAL)); //execution level which gamecode is told about (for unrecognised commands)
|
||||
|
@ -2853,7 +2856,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
|
|||
}
|
||||
#endif
|
||||
else
|
||||
found = FS_FLocateFile(name, FSLFRT_IFFOUND, loc);
|
||||
found = FS_FLocateFile(name, FSLF_IFFOUND, loc);
|
||||
|
||||
//nexuiz names certain files as .wav but they're really .ogg on disk.
|
||||
if (!found && replacementname)
|
||||
|
@ -2865,7 +2868,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
|
|||
COM_StripExtension(name, tryogg, sizeof(tryogg));
|
||||
COM_DefaultExtension(tryogg, ".ogg", sizeof(tryogg));
|
||||
|
||||
found = FS_FLocateFile(tryogg, FSLFRT_IFFOUND, loc);
|
||||
found = FS_FLocateFile(tryogg, FSLF_IFFOUND, loc);
|
||||
if (found)
|
||||
{
|
||||
name = *replacementname = va("%s", tryogg);
|
||||
|
@ -2909,7 +2912,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
|
|||
if (pakname && SV_AllowDownload(pakname))
|
||||
{
|
||||
//return loc of the pak instead.
|
||||
if (FS_FLocateFile(name, FSLFRT_IFFOUND, loc))
|
||||
if (FS_FLocateFile(name, FSLF_IFFOUND, loc))
|
||||
{
|
||||
//its inside a pak file, return the name of this file instead
|
||||
*replacementname = pakname;
|
||||
|
@ -4367,6 +4370,14 @@ void Cmd_Spiderpig_f(void)
|
|||
}
|
||||
void Cmd_Noclip_f (void)
|
||||
{
|
||||
#ifdef HLSERVER
|
||||
if (svs.gametype == GT_HALFLIFE)
|
||||
{
|
||||
HLSV_ClientCommand(host_client);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!SV_MayCheat())
|
||||
{
|
||||
SV_TPrintToClient(host_client, PRINT_HIGH, "Cheats are not allowed on this server\n");
|
||||
|
@ -6991,7 +7002,7 @@ void SV_ExecuteClientMessage (client_t *cl)
|
|||
cl->delay = 0.2;
|
||||
}
|
||||
|
||||
if (sv_antilag.ival)
|
||||
if (sv_antilag.ival || !*sv_antilag.string)
|
||||
{
|
||||
/*
|
||||
extern cvar_t temp1;
|
||||
|
@ -7009,7 +7020,7 @@ void SV_ExecuteClientMessage (client_t *cl)
|
|||
}
|
||||
cl->laggedents_count = sv.allocated_client_slots;
|
||||
|
||||
cl->laggedents_frac = sv_antilag_frac.value;
|
||||
cl->laggedents_frac = !*sv_antilag_frac.string?1:sv_antilag_frac.value;
|
||||
}
|
||||
else
|
||||
cl->laggedents_count = 0;
|
||||
|
@ -7720,6 +7731,9 @@ void SV_UserInit (void)
|
|||
Cvar_Register (&sv_spectalk, cvargroup_servercontrol);
|
||||
Cvar_Register (&sv_mapcheck, cvargroup_servercontrol);
|
||||
|
||||
Cvar_Register (&sv_minpitch, cvargroup_servercontrol);
|
||||
Cvar_Register (&sv_maxpitch, cvargroup_servercontrol);
|
||||
|
||||
Cvar_Register (&sv_fullredirect, cvargroup_servercontrol);
|
||||
Cvar_Register (&sv_antilag, cvargroup_servercontrol);
|
||||
Cvar_Register (&sv_antilag_frac, cvargroup_servercontrol);
|
||||
|
|
|
@ -47,7 +47,7 @@ int lastusermessage;
|
|||
|
||||
|
||||
|
||||
string_t QDECL GHL_AllocString(char *string)
|
||||
string_t QDECL GHL_AllocString(const char *string)
|
||||
{
|
||||
char *news;
|
||||
bi_begin();
|
||||
|
@ -58,7 +58,7 @@ string_t QDECL GHL_AllocString(char *string)
|
|||
bi_end();
|
||||
return news - SVHL_Globals.stringbase;
|
||||
}
|
||||
int QDECL GHL_PrecacheModel(char *name)
|
||||
int QDECL GHL_PrecacheModel(const char *name)
|
||||
{
|
||||
int i;
|
||||
bi_trace();
|
||||
|
@ -69,7 +69,7 @@ int QDECL GHL_PrecacheModel(char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
for (i=1 ; i<MAX_MODELS ; i++)
|
||||
for (i=1 ; i<MAX_PRECACHE_MODELS ; i++)
|
||||
{
|
||||
if (!sv.strings.model_precache[i])
|
||||
{
|
||||
|
@ -117,7 +117,7 @@ int QDECL GHL_PrecacheSound(char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
for (i=1 ; i<MAX_SOUNDS ; i++)
|
||||
for (i=1 ; i<MAX_PRECACHE_SOUNDS ; i++)
|
||||
{
|
||||
if (!*sv.strings.sound_precache[i])
|
||||
{
|
||||
|
@ -204,10 +204,156 @@ void QDECL GHL_VecToAngles(float *inv, float *outa)
|
|||
bi_trace();
|
||||
VectorAngles(inv, NULL, outa);
|
||||
}
|
||||
#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
|
||||
void QDECL GHL_MoveToOrigin(hledict_t *ent, vec3_t dest, float dist, int moveflags)
|
||||
{
|
||||
//mode 0: move_normal
|
||||
//mode 1: no idea
|
||||
//mode 2: test only
|
||||
// float dz;
|
||||
vec3_t oldorg, neworg, end;
|
||||
trace_t trace;
|
||||
// int i;
|
||||
int eflags = ent->v.flags;
|
||||
const vec3_t up = {0, 0, 1};
|
||||
vec3_t move;
|
||||
qboolean relink = true;
|
||||
qboolean domove = true;
|
||||
|
||||
bi_trace();
|
||||
ignore("GHL_MoveToOrigin");
|
||||
|
||||
if (moveflags)
|
||||
{ //strafe. just move directly.
|
||||
VectorSubtract(dest, ent->v.origin, move);
|
||||
move[2] = 0;
|
||||
VectorNormalize(move);
|
||||
VectorMA(ent->v.origin, dist, move, move);
|
||||
}
|
||||
else
|
||||
{
|
||||
float yaw = DEG2RAD(ent->v.angles[1]);
|
||||
move[0] = cos(yaw) * dist;
|
||||
move[1] = sin(yaw) * dist;
|
||||
move[2] = 0;
|
||||
}
|
||||
|
||||
// try the move
|
||||
VectorCopy (ent->v.origin, oldorg);
|
||||
VectorAdd (ent->v.origin, move, neworg);
|
||||
|
||||
#if 0
|
||||
// flying monsters don't step up
|
||||
if (eflags & (FL_SWIM | FL_FLY))
|
||||
{
|
||||
// try one move with vertical motion, then one without
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
VectorAdd (ent->v.origin, move, neworg);
|
||||
if (!noenemy)
|
||||
{
|
||||
enemy = (wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy);
|
||||
if (i == 0 && enemy->entnum)
|
||||
{
|
||||
VectorSubtract(ent->v->origin, ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->origin, end);
|
||||
dz = DotProduct(end, axis[2]);
|
||||
if (eflags & FLH2_HUNTFACE) /*get the ent's origin_z to match its victims face*/
|
||||
dz += ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->view_ofs[2];
|
||||
if (dz > 40)
|
||||
VectorMA(neworg, -8, up, neworg);
|
||||
if (dz < 30)
|
||||
VectorMA(neworg, 8, up, neworg);
|
||||
}
|
||||
}
|
||||
trace = World_Move (world, ent->v->origin, ent->v->mins, ent->v->maxs, neworg, false, ent);
|
||||
if (set_move_trace)
|
||||
set_move_trace(world->progs, set_trace_globs, &trace);
|
||||
|
||||
if (trace.fraction == 1)
|
||||
{
|
||||
if ( (eflags & FL_SWIM) && !(World_PointContents(world, trace.endpos) & FTECONTENTS_FLUID))
|
||||
continue; // swim monster left water
|
||||
|
||||
if (domove)
|
||||
VectorCopy (trace.endpos, ent->v->origin);
|
||||
if (relink)
|
||||
World_LinkEdict (world, ent, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (noenemy || !enemy->entnum)
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// push down from a step height above the wished position
|
||||
VectorMA(neworg, movevars.stepheight, up, neworg);
|
||||
VectorMA(neworg, movevars.stepheight*-2, up, end);
|
||||
|
||||
trace = SVHL_Move(neworg, ent->v.mins, ent->v.maxs, end, 0, 0, ent);
|
||||
|
||||
if (trace.allsolid)
|
||||
return false;
|
||||
|
||||
if (trace.startsolid)
|
||||
{
|
||||
//move up by an extra step, if needed
|
||||
VectorMA(neworg, -movevars.stepheight, up, neworg);
|
||||
trace = SVHL_Move (neworg, ent->v.mins, ent->v.maxs, end, 0, 0, ent);
|
||||
if (trace.allsolid || trace.startsolid)
|
||||
return false;
|
||||
}
|
||||
if (trace.fraction == 1)
|
||||
{
|
||||
// if monster had the ground pulled out, go ahead and fall
|
||||
if ( (int)eflags & FL_PARTIALGROUND )
|
||||
{
|
||||
if (domove)
|
||||
{
|
||||
VectorAdd (ent->v.origin, move, ent->v.origin);
|
||||
if (relink)
|
||||
SVHL_LinkEdict (ent, true);
|
||||
ent->v.flags = (int)eflags & ~FL_ONGROUND;
|
||||
}
|
||||
// Con_Printf ("fall down\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // walked off an edge
|
||||
}
|
||||
|
||||
// check point traces down for dangling corners
|
||||
if (domove)
|
||||
VectorCopy (trace.endpos, ent->v.origin);
|
||||
|
||||
/* if (!World_CheckBottom (world, ent, up))
|
||||
{
|
||||
if ( (int)ent->v->flags & FL_PARTIALGROUND )
|
||||
{ // entity had floor mostly pulled out from underneath it
|
||||
// and is trying to correct
|
||||
if (relink)
|
||||
SVHL_LinkEdict (ent, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (domove)
|
||||
VectorCopy (oldorg, ent->v->origin);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
if ( (int)ent->v.flags & FL_PARTIALGROUND )
|
||||
{
|
||||
// Con_Printf ("back on ground\n");
|
||||
ent->v.flags &= ~FL_PARTIALGROUND;
|
||||
}
|
||||
ent->v.groundentity = trace.ent;
|
||||
|
||||
// the move is ok
|
||||
if (relink)
|
||||
SVHL_LinkEdict (ent, true);
|
||||
return true;
|
||||
}
|
||||
unk QDECL GHL_ChangeYaw(unk){notimpf(__func__);}
|
||||
unk QDECL GHL_ChangePitch(unk){notimpf(__func__);}
|
||||
|
@ -243,7 +389,23 @@ hledict_t *QDECL GHL_FindEntityByString(hledict_t *last, char *field, char *valu
|
|||
}
|
||||
return SVHL_Edict;
|
||||
}
|
||||
unk QDECL GHL_GetEntityIllum(unk){notimpf(__func__);}
|
||||
void Sh_CalcPointLight(vec3_t point, vec3_t light);
|
||||
int QDECL GHL_GetEntityIllum(hledict_t *ent)
|
||||
{
|
||||
vec3_t diffuse, ambient, dir;
|
||||
float lev = 0;
|
||||
#if defined(RTLIGHTS) && !defined(SERVERONLY)
|
||||
Sh_CalcPointLight(ent->v.origin, ambient);
|
||||
lev += VectorLength(ambient);
|
||||
|
||||
if (!r_shadow_realtime_world.ival || r_shadow_realtime_world_lightmaps.value)
|
||||
#endif
|
||||
{
|
||||
sv.world.worldmodel->funcs.LightPointValues(sv.world.worldmodel, ent->v.origin, ambient, diffuse, dir);
|
||||
lev += (VectorLength(ambient) + VectorLength(diffuse)/2.0)/256;
|
||||
}
|
||||
return lev * 255; //I assume its 0-255, no idea
|
||||
}
|
||||
hledict_t *QDECL GHL_FindEntityInSphere(hledict_t *last, float *org, float radius)
|
||||
{
|
||||
int i, j;
|
||||
|
@ -281,7 +443,7 @@ hledict_t *QDECL GHL_FindClientInPVS(hledict_t *ed)
|
|||
int best = 0, i;
|
||||
float bestdist = 99999999; //HL maps are limited in size anyway
|
||||
float d;
|
||||
int leafnum;
|
||||
int clusternum;
|
||||
vec3_t ofs;
|
||||
hledict_t *other;
|
||||
|
||||
|
@ -290,7 +452,7 @@ hledict_t *QDECL GHL_FindClientInPVS(hledict_t *ed)
|
|||
//fixme: we need to track some state
|
||||
//a different client should be returned each call _per ent_ (so it can be used once per frame)
|
||||
|
||||
viewerpvs = sv.world.worldmodel->funcs.LeafPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.LeafnumForPoint(sv.world.worldmodel, ed->v.origin), NULL, 0);
|
||||
viewerpvs = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, ed->v.origin), NULL, 0);
|
||||
|
||||
for (i = 0; i < svs.allocated_client_slots; i++)
|
||||
{
|
||||
|
@ -302,8 +464,8 @@ hledict_t *QDECL GHL_FindClientInPVS(hledict_t *ed)
|
|||
if (svs.clients[i].spectator)
|
||||
continue; //ignore spectators
|
||||
|
||||
leafnum = sv.world.worldmodel->funcs.LeafnumForPoint(sv.world.worldmodel, other->v.origin)-1;/*pvs is 1 based, leafs are 0 based*/
|
||||
if (viewerpvs[leafnum>>3] & (1<<(leafnum&7)))
|
||||
clusternum = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, other->v.origin)-1;/*pvs is 1 based, leafs are 0 based*/
|
||||
if (viewerpvs[clusternum>>3] & (1<<(clusternum&7)))
|
||||
{
|
||||
VectorSubtract(ed->v.origin, other->v.origin, ofs);
|
||||
d = DotProduct(ofs, ofs);
|
||||
|
@ -455,11 +617,145 @@ int QDECL GHL_DropToFloor(hledict_t *ed)
|
|||
VectorCopy(tr.endpos, ed->v.origin);
|
||||
return tr.fraction != 0 && tr.fraction != 1;
|
||||
}
|
||||
int QDECL GHL_WalkMove(hledict_t *ed, float yaw, float dist, int mode)
|
||||
int QDECL GHL_WalkMove(hledict_t *ent, float yaw, float dist, int mode)
|
||||
{
|
||||
//mode 0: no idea
|
||||
//mode 1: no idea
|
||||
//mode 2: test only
|
||||
// float dz;
|
||||
vec3_t oldorg, neworg, end;
|
||||
trace_t trace;
|
||||
// int i;
|
||||
int eflags = ent->v.flags;
|
||||
const vec3_t up = {0, 0, 1};
|
||||
vec3_t move;
|
||||
qboolean relink = mode != 2;
|
||||
qboolean domove = mode != 2;
|
||||
|
||||
bi_trace();
|
||||
ignore("walkmove");
|
||||
return 1;
|
||||
|
||||
yaw = DEG2RAD(yaw);
|
||||
move[0] = cos(yaw) * dist;
|
||||
move[1] = sin(yaw) * dist;
|
||||
move[2] = 0;
|
||||
|
||||
// try the move
|
||||
VectorCopy (ent->v.origin, oldorg);
|
||||
VectorAdd (ent->v.origin, move, neworg);
|
||||
|
||||
#if 0
|
||||
// flying monsters don't step up
|
||||
if (eflags & (FL_SWIM | FL_FLY))
|
||||
{
|
||||
// try one move with vertical motion, then one without
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
VectorAdd (ent->v.origin, move, neworg);
|
||||
if (!noenemy)
|
||||
{
|
||||
enemy = (wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy);
|
||||
if (i == 0 && enemy->entnum)
|
||||
{
|
||||
VectorSubtract(ent->v->origin, ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->origin, end);
|
||||
dz = DotProduct(end, axis[2]);
|
||||
if (eflags & FLH2_HUNTFACE) /*get the ent's origin_z to match its victims face*/
|
||||
dz += ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->view_ofs[2];
|
||||
if (dz > 40)
|
||||
VectorMA(neworg, -8, up, neworg);
|
||||
if (dz < 30)
|
||||
VectorMA(neworg, 8, up, neworg);
|
||||
}
|
||||
}
|
||||
trace = World_Move (world, ent->v->origin, ent->v->mins, ent->v->maxs, neworg, false, ent);
|
||||
if (set_move_trace)
|
||||
set_move_trace(world->progs, set_trace_globs, &trace);
|
||||
|
||||
if (trace.fraction == 1)
|
||||
{
|
||||
if ( (eflags & FL_SWIM) && !(World_PointContents(world, trace.endpos) & FTECONTENTS_FLUID))
|
||||
continue; // swim monster left water
|
||||
|
||||
if (domove)
|
||||
VectorCopy (trace.endpos, ent->v->origin);
|
||||
if (relink)
|
||||
World_LinkEdict (world, ent, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (noenemy || !enemy->entnum)
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// push down from a step height above the wished position
|
||||
VectorMA(neworg, movevars.stepheight, up, neworg);
|
||||
VectorMA(neworg, movevars.stepheight*-2, up, end);
|
||||
|
||||
trace = SVHL_Move(neworg, ent->v.mins, ent->v.maxs, end, 0, 0, ent);
|
||||
|
||||
if (trace.allsolid)
|
||||
return false;
|
||||
|
||||
if (trace.startsolid)
|
||||
{
|
||||
//move up by an extra step, if needed
|
||||
VectorMA(neworg, -movevars.stepheight, up, neworg);
|
||||
trace = SVHL_Move (neworg, ent->v.mins, ent->v.maxs, end, 0, 0, ent);
|
||||
if (trace.allsolid || trace.startsolid)
|
||||
return false;
|
||||
}
|
||||
if (trace.fraction == 1)
|
||||
{
|
||||
// if monster had the ground pulled out, go ahead and fall
|
||||
if ( (int)eflags & FL_PARTIALGROUND )
|
||||
{
|
||||
if (domove)
|
||||
{
|
||||
VectorAdd (ent->v.origin, move, ent->v.origin);
|
||||
if (relink)
|
||||
SVHL_LinkEdict (ent, true);
|
||||
ent->v.flags = (int)eflags & ~FL_ONGROUND;
|
||||
}
|
||||
// Con_Printf ("fall down\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // walked off an edge
|
||||
}
|
||||
|
||||
// check point traces down for dangling corners
|
||||
if (domove)
|
||||
VectorCopy (trace.endpos, ent->v.origin);
|
||||
|
||||
/* if (!World_CheckBottom (world, ent, up))
|
||||
{
|
||||
if ( (int)ent->v->flags & FL_PARTIALGROUND )
|
||||
{ // entity had floor mostly pulled out from underneath it
|
||||
// and is trying to correct
|
||||
if (relink)
|
||||
SVHL_LinkEdict (ent, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (domove)
|
||||
VectorCopy (oldorg, ent->v->origin);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
if ( (int)ent->v.flags & FL_PARTIALGROUND )
|
||||
{
|
||||
// Con_Printf ("back on ground\n");
|
||||
ent->v.flags &= ~FL_PARTIALGROUND;
|
||||
}
|
||||
ent->v.groundentity = trace.ent;
|
||||
|
||||
// the move is ok
|
||||
if (relink)
|
||||
SVHL_LinkEdict (ent, true);
|
||||
return true;
|
||||
}
|
||||
void QDECL GHL_SetOrigin(hledict_t *ed, float *neworg)
|
||||
{
|
||||
|
@ -470,12 +766,14 @@ void QDECL GHL_SetOrigin(hledict_t *ed, float *neworg)
|
|||
void QDECL GHL_EmitSound(hledict_t *ed, int chan, char *soundname, float vol, float atten, int flags, int pitch)
|
||||
{
|
||||
bi_trace();
|
||||
SV_StartSound(ed-SVHL_Edict, ed->v.origin, ~0, chan, soundname, vol*255, atten, pitch);
|
||||
if (*soundname == '!')
|
||||
return; //would need us to parse sound/sentances.txt I guess
|
||||
SV_StartSound(ed-SVHL_Edict, ed->v.origin, ~0, chan, soundname, vol*255, atten, pitch, 0, 0);
|
||||
}
|
||||
void QDECL GHL_EmitAmbientSound(hledict_t *ed, float *org, char *soundname, float vol, float atten, unsigned int flags, int pitch)
|
||||
{
|
||||
bi_trace();
|
||||
SV_StartSound(0, org, ~0, 0, soundname, vol*255, atten, 0);
|
||||
SV_StartSound(0, org, ~0, 0, soundname, vol*255, atten, pitch, 0, 0);
|
||||
}
|
||||
void QDECL GHL_TraceLine(float *start, float *end, int flags, hledict_t *ignore, hltraceresult_t *result)
|
||||
{
|
||||
|
@ -522,7 +820,7 @@ char *QDECL GHL_TraceTexture(hledict_t *againstent, vec3_t start, vec3_t end)
|
|||
{
|
||||
trace_t tr;
|
||||
bi_trace();
|
||||
sv.world.worldmodel->funcs.NativeTrace(sv.world.worldmodel, 0, 0, NULL, start, end, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr);
|
||||
sv.world.worldmodel->funcs.NativeTrace(sv.world.worldmodel, 0, 0, NULL, start, end, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &tr);
|
||||
return tr.surface->name;
|
||||
}
|
||||
unk QDECL GHL_TraceSphere(unk){notimpf(__func__);}
|
||||
|
@ -530,6 +828,8 @@ unk QDECL GHL_GetAimVector(unk){notimpf(__func__);}
|
|||
void QDECL GHL_ServerCommand(char *cmd)
|
||||
{
|
||||
bi_trace();
|
||||
if (!strcmp(cmd, "reload\n"))
|
||||
cmd = "restart\n";
|
||||
Cbuf_AddText(cmd, RESTRICT_PROGS);
|
||||
}
|
||||
void QDECL GHL_ServerExecute(void)
|
||||
|
@ -541,8 +841,9 @@ unk QDECL GHL_ClientCommand(unk){notimpf(__func__);}
|
|||
unk QDECL GHL_ParticleEffect(unk){notimpf(__func__);}
|
||||
void QDECL GHL_LightStyle(int stylenum, char *stylestr)
|
||||
{
|
||||
vec3_t rgb = {1,1,1};
|
||||
bi_trace();
|
||||
PF_applylightstyle(stylenum, stylestr, 7);
|
||||
PF_applylightstyle(stylenum, stylestr, rgb);
|
||||
}
|
||||
int QDECL GHL_DecalIndex(char *decalname)
|
||||
{
|
||||
|
@ -619,6 +920,9 @@ void QDECL GHL_MessageEnd(unk)
|
|||
case MSG_MULTICAST+1:
|
||||
SV_Multicast(svhl_messageorigin, MULTICAST_PHS);
|
||||
break;
|
||||
case 9:
|
||||
//spectators only
|
||||
break;
|
||||
default:
|
||||
Con_Printf("GHL_MessageEnd: dest type %i not supported\n", svhl_messagedest);
|
||||
break;
|
||||
|
@ -629,7 +933,7 @@ void QDECL GHL_MessageEnd(unk)
|
|||
void QDECL GHL_WriteByte(int value)
|
||||
{
|
||||
bi_trace();
|
||||
MSG_WriteByte(&sv.multicast, value);
|
||||
MSG_WriteByte(&sv.multicast, value & 0xff);
|
||||
}
|
||||
void QDECL GHL_WriteChar(int value)
|
||||
{
|
||||
|
@ -730,7 +1034,102 @@ int QDECL GHL_RegUserMsg(char *msgname, int msgsize)
|
|||
return lastusermessage--;
|
||||
}
|
||||
unk QDECL GHL_AnimationAutomove(unk){notimpf(__func__);}
|
||||
unk QDECL GHL_GetBonePosition(unk){notimpf(__func__);}
|
||||
|
||||
static void GHL_GetFrameState(hledict_t *ent, framestate_t *fstate)
|
||||
{
|
||||
memset(fstate, 0, sizeof(*fstate));
|
||||
|
||||
fstate->g[FS_REG].frametime[0] = (SVHL_Globals.time - ent->v.framestarttime) * ent->v.framerate;
|
||||
fstate->g[FS_REG].frame[0] = ent->v.frame;
|
||||
fstate->g[FS_REG].lerpweight[0] = 1;
|
||||
fstate->g[FS_REG].subblendfrac = ent->v.blending[0]; //fixme: which is upper?
|
||||
|
||||
//FIXME: no lower parts.
|
||||
|
||||
fstate->bonecontrols[0] = ent->v.controller[0] / 255.0;
|
||||
fstate->bonecontrols[1] = ent->v.controller[1] / 255.0;
|
||||
fstate->bonecontrols[2] = ent->v.controller[2] / 255.0;
|
||||
fstate->bonecontrols[3] = ent->v.controller[3] / 255.0;
|
||||
}
|
||||
static void bonemat_fromqcvectors(float *out, const float vx[3], const float vy[3], const float vz[3], const float t[3])
|
||||
{
|
||||
out[0] = vx[0];
|
||||
out[1] = -vy[0];
|
||||
out[2] = vz[0];
|
||||
out[3] = t[0];
|
||||
out[4] = vx[1];
|
||||
out[5] = -vy[1];
|
||||
out[6] = vz[1];
|
||||
out[7] = t[1];
|
||||
out[8] = vx[2];
|
||||
out[9] = -vy[2];
|
||||
out[10] = vz[2];
|
||||
out[11] = t[2];
|
||||
}
|
||||
static void bonemat_fromidentity(float *out)
|
||||
{
|
||||
out[0] = 1;
|
||||
out[1] = 0;
|
||||
out[2] = 0;
|
||||
out[3] = 0;
|
||||
|
||||
out[4] = 0;
|
||||
out[5] = 1;
|
||||
out[6] = 0;
|
||||
out[7] = 0;
|
||||
|
||||
out[8] = 0;
|
||||
out[9] = 0;
|
||||
out[10] = 1;
|
||||
out[11] = 0;
|
||||
}
|
||||
static void bonemat_toqcvectors(const float *in, float vx[3], float vy[3], float vz[3], float t[3])
|
||||
{
|
||||
vx[0] = in[0];
|
||||
vx[1] = in[4];
|
||||
vx[2] = in[8];
|
||||
vy[0] = -in[1];
|
||||
vy[1] = -in[5];
|
||||
vy[2] = -in[9];
|
||||
vz[0] = in[2];
|
||||
vz[1] = in[6];
|
||||
vz[2] = in[10];
|
||||
t [0] = in[3];
|
||||
t [1] = in[7];
|
||||
t [2] = in[11];
|
||||
}
|
||||
static void bonemat_fromhlentity(hledict_t *ed, float *trans)
|
||||
{
|
||||
vec3_t d[3], a;
|
||||
a[0] = -ed->v.angles[0];
|
||||
a[1] = ed->v.angles[1];
|
||||
a[2] = ed->v.angles[2];
|
||||
AngleVectors(a, d[0], d[1], d[2]);
|
||||
bonemat_fromqcvectors(trans, d[0], d[1], d[2], ed->v.origin);
|
||||
}
|
||||
void QDECL GHL_GetBonePosition(hledict_t *ed, int bone, vec3_t org, vec3_t ang)
|
||||
{
|
||||
float transent[12];
|
||||
float transforms[12];
|
||||
float result[12];
|
||||
model_t *mod = sv.models[ed->v.modelindex];
|
||||
vec3_t axis[3];
|
||||
framestate_t fstate;
|
||||
GHL_GetFrameState(ed, &fstate);
|
||||
|
||||
bone += 1; //I *think* the bones are 0-based unlike our tag-based bone numbers
|
||||
|
||||
if (!Mod_GetTag(mod, bone, &fstate, transforms))
|
||||
{
|
||||
bonemat_fromidentity(transforms);
|
||||
}
|
||||
|
||||
bonemat_fromhlentity(ed, transent);
|
||||
R_ConcatTransforms((void*)transent, (void*)transforms, (void*)result);
|
||||
|
||||
bonemat_toqcvectors(result, axis[0], axis[1], axis[2], org);
|
||||
VectorAngles(axis[0], axis[2], ang);
|
||||
}
|
||||
|
||||
hlintptr_t QDECL GHL_FunctionFromName(char *name)
|
||||
{
|
||||
|
@ -772,7 +1171,7 @@ int QDECL GHL_Cmd_Argc(unk)
|
|||
unk QDECL GHL_GetAttachment(unk){notimpf(__func__);}
|
||||
void QDECL GHL_CRC32_Init(hlcrc_t *crc)
|
||||
{
|
||||
unsigned short crc16 = *crc;
|
||||
unsigned short crc16;
|
||||
bi_trace();
|
||||
QCRC_Init(&crc16);
|
||||
*crc = crc16;
|
||||
|
@ -1324,11 +1723,12 @@ void SV_ReadLibListDotGam(void)
|
|||
char value[1024];
|
||||
char *file;
|
||||
char *s;
|
||||
size_t fsize;
|
||||
|
||||
Info_SetValueForStarKey(svs.info, "*gamedll", "", sizeof(svs.info));
|
||||
Info_SetValueForStarKey(svs.info, "*cldll", "", sizeof(svs.info));
|
||||
|
||||
file = COM_LoadTempFile("liblist.gam");
|
||||
file = COM_LoadTempFile("liblist.gam", &fsize);
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
|
@ -1368,6 +1768,8 @@ int SVHL_InitGame(void)
|
|||
{NULL, NULL}
|
||||
};
|
||||
|
||||
memset(&SVHL_Globals, 0, sizeof(SVHL_Globals));
|
||||
|
||||
if (sizeof(long) != sizeof(void*))
|
||||
{
|
||||
Con_Printf("sizeof(long)!=sizeof(ptr): Cannot run halflife gamecode on this platform\n");
|
||||
|
@ -1387,7 +1789,8 @@ int SVHL_InitGame(void)
|
|||
|
||||
gamedll = Info_ValueForKey(svs.info, "*gamedll");
|
||||
iterator = NULL;
|
||||
while(COM_IteratePaths(&iterator, path, sizeof(path)))
|
||||
//FIXME: game dlls from game paths are evil/exploitable.
|
||||
while(COM_IteratePaths(&iterator, path, sizeof(path), NULL, 0))
|
||||
{
|
||||
snprintf (fullname, sizeof(fullname), "%s%s", path, gamedll);
|
||||
hlgamecode = Sys_LoadLibrary(fullname, hlgamefuncs);
|
||||
|
@ -1404,7 +1807,7 @@ int SVHL_InitGame(void)
|
|||
|
||||
if (!GetEntityAPI(&SVHL_GameFuncs, HALFLIFE_API_VERSION))
|
||||
{
|
||||
Con_Printf(CON_ERROR "Error: %s is incompatible (FTE is compiled for %i)\n", fullname, HALFLIFE_API_VERSION);
|
||||
Con_Printf(CON_ERROR "Error: %s is incompatible (Engine is compiled for %i)\n", fullname, HALFLIFE_API_VERSION);
|
||||
if (GetEntityAPI(&SVHL_GameFuncs, 138))
|
||||
Con_Printf(CON_ERROR "mod is 138\n");
|
||||
Sys_CloseLibrary(hlgamecode);
|
||||
|
@ -1446,7 +1849,12 @@ void SVHL_SpawnEntities(char *entstring)
|
|||
SVHL_Globals.deathmatch = deathmatch.value;
|
||||
SVHL_Globals.coop = coop.value;
|
||||
SVHL_Globals.serverflags = 0;
|
||||
SVHL_Globals.mapname = GHL_AllocString(sv.name);
|
||||
if (!strncmp(sv.modelname, "maps/", 5))
|
||||
COM_StripExtension(sv.modelname+5, value, sizeof(value));
|
||||
else
|
||||
COM_StripExtension(sv.modelname, value, sizeof(value));
|
||||
SVHL_Globals.mapname = GHL_AllocString(value);
|
||||
SVHL_Globals.time = 0;
|
||||
|
||||
SVHL_NumActiveEnts = 0;
|
||||
|
||||
|
@ -1474,8 +1882,12 @@ void SVHL_SpawnEntities(char *entstring)
|
|||
sv.strings.model_precache[1] = sv.modelname; //the qvm doesn't have access to this array
|
||||
for (i=1 ; i<sv.world.worldmodel->numsubmodels ; i++)
|
||||
{
|
||||
sv.strings.model_precache[1+i] = localmodels[i];
|
||||
sv.models[i+1] = Mod_ForName (Mod_FixName(localmodels[i], sv.modelname), false);
|
||||
const char *s = va("*%i", i);
|
||||
char *n;
|
||||
n = ZG_Malloc(&hlmapmemgroup, strlen(s)+1);
|
||||
strcpy(n, s);
|
||||
sv.strings.model_precache[1+i] = n;
|
||||
sv.models[i+1] = Mod_ForName (Mod_FixName(n, sv.modelname), false);
|
||||
}
|
||||
|
||||
while (entstring)
|
||||
|
@ -1574,6 +1986,19 @@ qboolean HLSV_ClientCommand(client_t *client)
|
|||
hledict_t *ed = &SVHL_Edict[client - svs.clients + 1];
|
||||
if (!hlgamecode)
|
||||
return false;
|
||||
if (!strcmp("noclip", Cmd_Argv(0)))
|
||||
{
|
||||
if (ed->v.movetype != MOVETYPE_NOCLIP)
|
||||
ed->v.movetype = MOVETYPE_NOCLIP;
|
||||
else
|
||||
ed->v.movetype = MOVETYPE_WALK;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp("kill", Cmd_Argv(0)))
|
||||
{
|
||||
SVHL_GameFuncs.ClientKill(ed);
|
||||
return true;
|
||||
}
|
||||
bi_begin();
|
||||
SVHL_GameFuncs.ClientCommand(ed);
|
||||
bi_end();
|
||||
|
@ -1589,7 +2014,8 @@ qboolean SVHL_ClientConnect(client_t *client, netadr_t adr, char rejectmessage[1
|
|||
|
||||
sv.skipbprintclient = client;
|
||||
bi_begin();
|
||||
result = SVHL_GameFuncs.ClientConnect(&SVHL_Edict[client-svs.clients+1], client->name, ipadr, rejectmessage);
|
||||
client->hledict = &SVHL_Edict[client-svs.clients+1];
|
||||
result = SVHL_GameFuncs.ClientConnect(client->hledict, client->name, ipadr, rejectmessage);
|
||||
bi_end();
|
||||
sv.skipbprintclient = NULL;
|
||||
|
||||
|
@ -1602,7 +2028,7 @@ void SVHL_BuildStats(client_t *client, int *si, float *sf, char **ss)
|
|||
|
||||
si[STAT_HEALTH] = ed->v.health;
|
||||
si[STAT_VIEWHEIGHT] = ed->v.view_ofs[2];
|
||||
si[STAT_WEAPON] = SV_ModelIndex(SVHL_Globals.stringbase+ed->v.vmodelindex);
|
||||
si[STAT_WEAPONMODELI] = SV_ModelIndex(SVHL_Globals.stringbase+ed->v.vmodelindex);
|
||||
si[STAT_ITEMS] = ed->v.weapons;
|
||||
}
|
||||
|
||||
|
@ -1621,6 +2047,7 @@ void SVHL_DropClient(client_t *drop)
|
|||
bi_begin();
|
||||
SVHL_GameFuncs.ClientDisconnect(&SVHL_Edict[drop-svs.clients+1]);
|
||||
bi_end();
|
||||
drop->hledict = NULL;
|
||||
ed->isfree = true;
|
||||
}
|
||||
|
||||
|
@ -1636,8 +2063,9 @@ extern cvar_t temp1;
|
|||
usercmd_t cmd = *ucmd;
|
||||
|
||||
cmd.msec = ucmd->msec/2;
|
||||
cmd.msec_compat = floor(cmd.msec);
|
||||
SVHL_RunCmdR (ed, &cmd);
|
||||
cmd.msec = ucmd->msec/2 + (ucmd->msec&1); //give them back their msec.
|
||||
cmd.msec_compat = ucmd->msec - cmd.msec_compat;
|
||||
cmd.impulse = 0;
|
||||
SVHL_RunCmdR (ed, &cmd);
|
||||
return;
|
||||
|
@ -1649,7 +2077,22 @@ extern cvar_t temp1;
|
|||
host_frametime = 0.1;
|
||||
|
||||
pmove.cmd = *ucmd;
|
||||
pmove.pm_type = temp1.value;//PM_NORMAL;//FLY;
|
||||
switch(ed->v.movetype)
|
||||
{
|
||||
default:
|
||||
case MOVETYPE_WALK:
|
||||
pmove.pm_type = PM_NORMAL;
|
||||
break;
|
||||
case MOVETYPE_FLY:
|
||||
pmove.pm_type = PM_FLY;
|
||||
break;
|
||||
case MOVETYPE_NOCLIP:
|
||||
pmove.pm_type = PM_SPECTATOR;
|
||||
break;
|
||||
case MOVETYPE_NONE:
|
||||
pmove.pm_type = PM_NONE;
|
||||
break;
|
||||
}
|
||||
pmove.numphysent = 1;
|
||||
pmove.physents[0].model = sv.world.worldmodel;
|
||||
pmove.physents[0].info = 0;
|
||||
|
@ -1742,8 +2185,8 @@ extern cvar_t temp1;
|
|||
}
|
||||
}
|
||||
|
||||
VectorCopy(ed->v.mins, player_mins);
|
||||
VectorCopy(ed->v.maxs, player_maxs);
|
||||
VectorCopy(ed->v.mins, pmove.player_mins);
|
||||
VectorCopy(ed->v.maxs, pmove.player_maxs);
|
||||
|
||||
VectorCopy(ed->v.origin, pmove.origin);
|
||||
VectorCopy(ed->v.velocity, pmove.velocity);
|
||||
|
@ -1823,6 +2266,8 @@ void SVHL_RunCmd(client_t *cl, usercmd_t *ucmd)
|
|||
ed->v.angles[1] = SHORT2ANGLE(ucmd->angles[1]);
|
||||
ed->v.angles[2] = SHORT2ANGLE(ucmd->angles[2]);
|
||||
|
||||
if (IS_NAN(ed->v.velocity[0]) || IS_NAN(ed->v.velocity[1]) || IS_NAN(ed->v.velocity[2]))
|
||||
VectorClear(ed->v.velocity);
|
||||
|
||||
bi_begin();
|
||||
SVHL_GameFuncs.PlayerPreThink(ed);
|
||||
|
@ -1890,12 +2335,43 @@ void SVHL_Snapshot_Build(client_t *client, packet_entities_t *pack, qbyte *pvs,
|
|||
s->number = i;
|
||||
s->modelindex = e->v.modelindex;
|
||||
s->frame = e->v.sequence1;
|
||||
s->effects = e->v.effects;
|
||||
s->effects = e->v.effects & 0x0f;
|
||||
s->dpflags = 0;
|
||||
s->skinnum = e->v.skin;
|
||||
s->scale = 16;
|
||||
s->trans = 255;
|
||||
s->colormod[0] = nullentitystate.colormod[0];
|
||||
s->colormod[1] = nullentitystate.colormod[1];
|
||||
s->colormod[2] = nullentitystate.colormod[2];
|
||||
VectorCopy(e->v.angles, s->angles);
|
||||
VectorCopy(e->v.origin, s->origin);
|
||||
|
||||
if (!e->v.velocity[0] && !e->v.velocity[1] && !e->v.velocity[2])
|
||||
s->dpflags |= RENDER_STEP;
|
||||
|
||||
s->trans = e->v.renderamt*255;
|
||||
switch (e->v.rendermode)
|
||||
{
|
||||
case 0:
|
||||
s->trans = 255;
|
||||
break;
|
||||
case 1: //used on laser beams, apparently
|
||||
break;
|
||||
case 2: //transparent windows.
|
||||
break;
|
||||
case 3: //used on coronarey sprites.
|
||||
s->effects |= NQEF_ADDITIVE;
|
||||
break;
|
||||
case 4: //used on fence textures, apparently. we already deal with these clientside.
|
||||
s->trans = 255;
|
||||
break;
|
||||
case 5: //used on the torch at the start.
|
||||
s->effects |= NQEF_ADDITIVE;
|
||||
break;
|
||||
default:
|
||||
Con_Printf("Rendermode %s %i\n", SVHL_Globals.stringbase+e->v.model, e->v.rendermode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -417,7 +417,7 @@ typedef struct
|
|||
unk (QDECL *ChangeYaw)(unk);
|
||||
unk (QDECL *ChangePitch)(unk);
|
||||
hledict_t *(QDECL *FindEntityByString)(hledict_t *last, char *field, char *value);
|
||||
unk (QDECL *GetEntityIllum)(unk);
|
||||
int (QDECL *GetEntityIllum)(hledict_t *ent);
|
||||
hledict_t *(QDECL *FindEntityInSphere)(hledict_t *last, float *org, float radius);
|
||||
hledict_t *(QDECL *FindClientInPVS)(hledict_t *ed);
|
||||
unk (QDECL *EntitiesInPVS)(unk);
|
||||
|
@ -479,7 +479,7 @@ typedef struct
|
|||
void *(QDECL *GetModelPtr)(hledict_t *ed);
|
||||
int (QDECL *RegUserMsg)(char *msgname, int msgsize);
|
||||
unk (QDECL *AnimationAutomove)(unk);
|
||||
unk (QDECL *GetBonePosition)(unk);
|
||||
void (QDECL *GetBonePosition)(hledict_t *ed, int bone, vec3_t org, vec3_t ang);
|
||||
hlintptr_t (QDECL *FunctionFromName)(char *name);
|
||||
char *(QDECL *NameForFunction)(hlintptr_t);
|
||||
unk (QDECL *ClientPrintf)(unk);
|
||||
|
|
|
@ -552,8 +552,8 @@ qboolean SVHL_PushAngles (hledict_t *pusher, vec3_t move, vec3_t amove)
|
|||
|
||||
|
||||
// see if the ent's bbox is inside the pusher's final position
|
||||
// if (!SVHL_TestEntityPosition (check))
|
||||
// continue;
|
||||
if (!SVHL_TestEntityPosition (check))
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pusher->v.movetype == MOVETYPE_PUSH) || (check->v.groundentity == pusher))
|
||||
|
@ -886,7 +886,7 @@ Entities that are "stuck" to another entity
|
|||
*/
|
||||
void SVHL_Physics_Follow (hledict_t *ent)
|
||||
{
|
||||
vec3_t vf, vr, vu, angles, v;
|
||||
// vec3_t vf, vr, vu, angles, v;
|
||||
hledict_t *e;
|
||||
|
||||
// regular thinking
|
||||
|
@ -1817,13 +1817,16 @@ void SVHL_RunFrame (void)
|
|||
|
||||
//only run physics tics if there's a client on the server.
|
||||
//this fixes the bug where the train moves out before the player spawns, so the player doesn't fall to his death
|
||||
for (i = 0; i < sv.allocated_client_slots; i++)
|
||||
if (sv.state == ss_active)
|
||||
{
|
||||
if (svs.clients[i].state == cs_spawned)
|
||||
break;
|
||||
for (i = 0; i < sv.allocated_client_slots; i++)
|
||||
{
|
||||
if (svs.clients[i].state == cs_spawned)
|
||||
break;
|
||||
}
|
||||
if (i == sv.allocated_client_slots)
|
||||
return;
|
||||
}
|
||||
if (i == sv.allocated_client_slots)
|
||||
return;
|
||||
|
||||
|
||||
SVHL_Globals.frametime = host_frametime;
|
||||
|
|
|
@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "svhl_gcapi.h"
|
||||
|
||||
hull_t *World_HullForBox (vec3_t mins, vec3_t maxs);
|
||||
qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask);
|
||||
//qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask);
|
||||
/*
|
||||
|
||||
entities never clip against themselves, or their owner
|
||||
|
@ -380,12 +380,12 @@ trace_t SVHL_ClipMoveToEntity (hledict_t *ent, vec3_t start, vec3_t mins, vec3_t
|
|||
if (ent->v.solid != SOLID_BSP)
|
||||
{
|
||||
ent->v.angles[0]*=-1; //carmack made bsp models rotate wrongly.
|
||||
TransformedTrace(model, hullnum, ent->v.frame, start, end, mins, maxs, &trace, ent->v.origin, ent->v.angles, clipmask);
|
||||
World_TransformedTrace(model, hullnum, ent->v.frame, start, end, mins, maxs, false, &trace, ent->v.origin, ent->v.angles, clipmask);
|
||||
ent->v.angles[0]*=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
TransformedTrace(model, hullnum, ent->v.frame, start, end, mins, maxs, &trace, ent->v.origin, ent->v.angles, clipmask);
|
||||
World_TransformedTrace(model, hullnum, ent->v.frame, start, end, mins, maxs, false, &trace, ent->v.origin, ent->v.angles, clipmask);
|
||||
}
|
||||
|
||||
// fix trace up by the offset
|
||||
|
@ -396,7 +396,7 @@ trace_t SVHL_ClipMoveToEntity (hledict_t *ent, vec3_t start, vec3_t mins, vec3_t
|
|||
//okay, we hit the bbox
|
||||
|
||||
model_t *model;
|
||||
if (ent->v.modelindex < 1 || ent->v.modelindex >= MAX_MODELS)
|
||||
if (ent->v.modelindex < 1 || ent->v.modelindex >= MAX_PRECACHE_MODELS)
|
||||
SV_Error("SV_ClipMoveToEntity: modelindex out of range\n");
|
||||
model = sv.models[ (int)ent->v.modelindex ];
|
||||
if (!model)
|
||||
|
@ -408,7 +408,7 @@ trace_t SVHL_ClipMoveToEntity (hledict_t *ent, vec3_t start, vec3_t mins, vec3_t
|
|||
if (model && model->funcs.NativeTrace)
|
||||
{
|
||||
//do the second trace
|
||||
TransformedTrace(model, hullnum, ent->v.frame, start, end, mins, maxs, &trace, ent->v.origin, ent->v.angles, MASK_WORLDSOLID);
|
||||
World_TransformedTrace(model, hullnum, ent->v.frame, start, end, mins, maxs, false, &trace, ent->v.origin, ent->v.angles, MASK_WORLDSOLID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2097,7 +2097,7 @@ qboolean QDECL World_RegisterPhysicsEngine(const char *enginename, void(QDECL*st
|
|||
world_current_physics_engine = startupfunc;
|
||||
return true;
|
||||
}
|
||||
static void World_ShutdownPhysics(world_t *world)
|
||||
void World_RBE_Shutdown(world_t *world)
|
||||
{
|
||||
unsigned int u;
|
||||
wedict_t *ed;
|
||||
|
@ -2124,11 +2124,11 @@ void QDECL World_UnregisterPhysicsEngine(const char *enginename)
|
|||
#if defined(CSQC_DAT) && !defined(SERVERONLY)
|
||||
{
|
||||
extern world_t csqc_world;
|
||||
World_ShutdownPhysics(&csqc_world);
|
||||
World_RBE_Shutdown(&csqc_world);
|
||||
}
|
||||
#endif
|
||||
#if !defined(CLIENTONLY)
|
||||
World_ShutdownPhysics(&sv.world);
|
||||
World_RBE_Shutdown(&sv.world);
|
||||
#endif
|
||||
|
||||
world_current_physics_engine = NULL;
|
||||
|
@ -2136,12 +2136,15 @@ void QDECL World_UnregisterPhysicsEngine(const char *enginename)
|
|||
void World_RBE_Start(world_t *world)
|
||||
{
|
||||
if (world_current_physics_engine)
|
||||
world_current_physics_engine(world);
|
||||
{
|
||||
if (world->worldmodel)
|
||||
world_current_physics_engine(world);
|
||||
}
|
||||
}
|
||||
|
||||
void World_Destroy(world_t *world)
|
||||
{
|
||||
World_ShutdownPhysics(world);
|
||||
World_RBE_Shutdown(world);
|
||||
|
||||
Z_Free(world->areanodes);
|
||||
world->areanodes = NULL;
|
||||
|
|
|
@ -375,7 +375,6 @@ void SWBE_SelectMode(backendmode_t mode)
|
|||
|
||||
void SWBE_TransformVerticies(swvert_t *v, mesh_t *mesh)
|
||||
{
|
||||
extern cvar_t temp1;
|
||||
int i;
|
||||
|
||||
vecV_t *xyz;
|
||||
|
|
|
@ -110,7 +110,8 @@ int(int mod, brushface_t *faces, int numfaces, int contents) brush_history_creat
|
|||
|
||||
h->id = brush_create(h->brushmodel, h->brushdata, h->numfaces, h->contents);
|
||||
|
||||
history++;
|
||||
if (h->id)
|
||||
history++;
|
||||
history_max = history; //always break any pending redos
|
||||
if (history_min < history_max - historyring.length)
|
||||
history_min = history_max - historyring.length;
|
||||
|
@ -941,6 +942,75 @@ void(brushface_t *faces, int numfaces) DebrushifyLite =
|
|||
}
|
||||
};
|
||||
|
||||
void(vector org, vector ang) editor_brushes_simpleclone =
|
||||
{
|
||||
vector midpoint;
|
||||
if (!selectedbrush)
|
||||
return;
|
||||
|
||||
tmp_numfaces = brush_get(selectedbrushmodel, selectedbrush, tmp_faces, tmp_faces.length, &tmp_contents);
|
||||
if (ang != '0 0 0')
|
||||
{
|
||||
brush_getfacepoints(selectedbrushmodel, selectedbrush, 0, &midpoint, 1);
|
||||
brushface_translate(tmp_faces, tmp_numfaces, -midpoint);
|
||||
makevectors(ang);
|
||||
brushface_rotate(tmp_faces, tmp_numfaces);
|
||||
brushface_translate(tmp_faces, tmp_numfaces, midpoint + org);
|
||||
}
|
||||
else
|
||||
brushface_translate(tmp_faces, tmp_numfaces, org);
|
||||
selectedbrush = brush_history_create(selectedbrushmodel, tmp_faces, tmp_numfaces, tmp_contents);
|
||||
};
|
||||
|
||||
void() brushedit_subtract =
|
||||
{
|
||||
int discard;
|
||||
vector selnormals[tmp_faces.length];
|
||||
float seldists[tmp_faces.length];
|
||||
|
||||
int planecount = brush_get(selectedbrushmodel, selectedbrush, tmp_faces, tmp_faces.length, &tmp_contents);
|
||||
for (int i = 0; i < planecount; i++)
|
||||
{
|
||||
selnormals[i] = tmp_faces[i].planenormal;
|
||||
seldists[i] = tmp_faces[i].planedist;
|
||||
}
|
||||
int numbrushes = brush_findinvolume(selectedbrushmodel, selnormals, seldists, planecount, brushlist, __NULL__, brushlist.length);
|
||||
|
||||
while (numbrushes --> 0)
|
||||
{
|
||||
int br = brushlist[numbrushes];
|
||||
if (br == selectedbrush)
|
||||
continue;
|
||||
|
||||
int counto = brush_get(selectedbrushmodel, br, tmp_faces, tmp_faces.length, &tmp_contents);
|
||||
int counts = counto + brush_get(selectedbrushmodel, selectedbrush, tmp_faces+counto, tmp_faces.length-counto, &discard);
|
||||
|
||||
brush_history_delete(selectedbrushmodel, br);
|
||||
while(counts --> counto)
|
||||
{
|
||||
//only consider the resulting brush if the new face actually contributed anything.
|
||||
//this reduces dupes.
|
||||
if (brush_calcfacepoints(1+counts, tmp_faces, counts+1, facepoints, facepoints.length))
|
||||
{
|
||||
//determine the brush defined by this plane
|
||||
tmp_faces[counts].planenormal *= -1;
|
||||
tmp_faces[counts].planedist *= -1;
|
||||
brush_history_create(selectedbrushmodel, tmp_faces, counts+1, tmp_contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void() brushedit_resettextures =
|
||||
{
|
||||
int planecount = brush_get(selectedbrushmodel, selectedbrush, tmp_faces, tmp_faces.length, &tmp_contents);
|
||||
for (int i = 0; i < planecount; i++)
|
||||
reset_texturecoords(&tmp_faces[i]);
|
||||
|
||||
brush_history_delete(selectedbrushmodel, selectedbrush);
|
||||
selectedbrush = brush_history_create(selectedbrushmodel, tmp_faces, planecount, tmp_contents);
|
||||
};
|
||||
|
||||
void(vector mousepos) editor_brushes_add =
|
||||
{
|
||||
vector col = '0 0 0';
|
||||
|
@ -1482,29 +1552,12 @@ brusheditormodes
|
|||
registercommand("brushedit_matchface");
|
||||
registercommand("brushedit_resettexcoords");
|
||||
registercommand("brushedit_settexture");
|
||||
registercommand("brushedit_subtract");
|
||||
registercommand("brushedit_binds");
|
||||
registercommand("+brushedit_nogrid");
|
||||
registercommand("-brushedit_nogrid");
|
||||
};
|
||||
void(vector org, vector ang) editor_brushes_simpleclone =
|
||||
{
|
||||
vector midpoint;
|
||||
if (!selectedbrush)
|
||||
return;
|
||||
|
||||
tmp_numfaces = brush_get(selectedbrushmodel, selectedbrush, tmp_faces, tmp_faces.length, &tmp_contents);
|
||||
if (ang != '0 0 0')
|
||||
{
|
||||
brush_getfacepoints(selectedbrushmodel, selectedbrush, 0, &midpoint, 1);
|
||||
brushface_translate(tmp_faces, tmp_numfaces, -midpoint);
|
||||
makevectors(ang);
|
||||
brushface_rotate(tmp_faces, tmp_numfaces);
|
||||
brushface_translate(tmp_faces, tmp_numfaces, midpoint + org);
|
||||
}
|
||||
else
|
||||
brushface_translate(tmp_faces, tmp_numfaces, org);
|
||||
selectedbrush = brush_history_create(selectedbrushmodel, tmp_faces, tmp_numfaces, tmp_contents);
|
||||
};
|
||||
float() editor_brushes_command =
|
||||
{
|
||||
switch(argv(0))
|
||||
|
@ -1537,15 +1590,16 @@ brusheditormodes
|
|||
bt_points = 0;
|
||||
break;
|
||||
case "brushedit_resettexcoords":
|
||||
//IMPLEMENTME
|
||||
brushtool = BT_NONE;
|
||||
bt_points = 0;
|
||||
brushedit_resettextures();
|
||||
break;
|
||||
case "brushedit_settexture":
|
||||
//IMPLEMENTME
|
||||
brushtool = BT_NONE;
|
||||
bt_points = 0;
|
||||
break;
|
||||
case "brushedit_subtract":
|
||||
brushedit_subtract();
|
||||
break;
|
||||
case "brushedit_delete":
|
||||
if (selectedbrushmodel && selectedbrush)
|
||||
brush_history_delete(selectedbrushmodel, selectedbrush);
|
||||
|
@ -1553,15 +1607,16 @@ brusheditormodes
|
|||
break;
|
||||
case "brushedit_binds":
|
||||
localcmd("conmenu \"\"\n");
|
||||
localcmd("menubind 0 8 \"brushedit_create\" \"Creation Tool\"\n");
|
||||
localcmd("menubind 0 16 \"brushedit_slice\" \"Slice Tool\"\n");
|
||||
localcmd("menubind 0 24 \"brushedit_delete\" \"Delete\"\n");
|
||||
localcmd("menubind 0 32 \"brushedit_undo\" \"Undo\"\n");
|
||||
localcmd("menubind 0 40 \"brushedit_redo\" \"Redo\"\n");
|
||||
localcmd("menubind 0 48 \"brushedit_nogrid\" \"Disable Grid\"\n");
|
||||
float foo = 0;
|
||||
localcmd(sprintf("menubind 0 %g \"brushedit_create\" \"Creation Tool\"\n", foo+=8));
|
||||
localcmd(sprintf("menubind 0 %g \"brushedit_slice\" \"Slice Tool\"\n", foo+=8));
|
||||
localcmd(sprintf("menubind 0 %g \"brushedit_delete\" \"Delete\"\n", foo+=8));
|
||||
localcmd(sprintf("menubind 0 %g \"brushedit_subtract\" \"Subtract\"\n", foo+=8));
|
||||
localcmd(sprintf("menubind 0 %g \"brushedit_undo\" \"Undo\"\n", foo+=8));
|
||||
localcmd(sprintf("menubind 0 %g \"brushedit_redo\" \"Redo\"\n", foo+=8));
|
||||
localcmd(sprintf("menubind 0 %g \"brushedit_nogrid\" \"Disable Grid\"\n", foo+=8));
|
||||
|
||||
float foo = 56;
|
||||
#define brusheditormode(n,v) localcmd(sprintf("menubind 0 %g \"+brushedit_"n"\" \""n"\"\n", foo)); foo+=8;
|
||||
#define brusheditormode(n,v) localcmd(sprintf("menubind 0 %g \"+brushedit_"n"\" \""n"\"\n", foo+=8));
|
||||
brusheditormodes
|
||||
#undef brusheditormode
|
||||
break;
|
||||
|
@ -1804,11 +1859,5 @@ float(float key, float unic, vector mousepos) editor_brushes_key =
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* if (key == 's')
|
||||
{
|
||||
//CSG subtraction is actually quite easy...
|
||||
//for each brush that intersects us, split it by every single one of our planes that intesect
|
||||
//drop the resulting brushes if they contain contain points only within the subtraction region
|
||||
}
|
||||
*/ return FALSE;
|
||||
return FALSE;
|
||||
};
|
||||
|
|
|
@ -133,6 +133,10 @@ inwater <effectname>
|
|||
Specifies a replacement effect to use when this one is spawned underwater.
|
||||
assoc used is the replacement effect. the assoc value from the replaced effect is ignored (this includes +foo chains).
|
||||
|
||||
overwater
|
||||
specifies that this
|
||||
underwater
|
||||
|
||||
colorindex <index> [rand]
|
||||
Specifies a palette index to spawn the particle with.
|
||||
The index used is between index and index+rand.
|
||||
|
@ -279,6 +283,10 @@ emitstart <seconds>
|
|||
spawnorg <horiz> [vert]
|
||||
spawnvel <horiz> [vert]
|
||||
|
||||
viewspace [frac]
|
||||
Specifies that this particle type should move relative to the camera.
|
||||
Not compatible with splitscreen.
|
||||
|
||||
perframe
|
||||
apply inverse frametime to count (causes emits to be per frame)
|
||||
|
||||
|
|
Loading…
Reference in a new issue