made max_clients more dynamic on the server to attempt to reduce bss usage. hopefully this will help the webgl port without resulting in extra crashes.

tweaked shadowmaps. now seems faster than stencil shadows. cubemap orientation should now match other engines.
tweaked terrain. rtlights work. added pvs tests for embedded terrain. sections are now saved in chunks instead, which should mean windows doesn't have a panic attack at 16 million files in a single directory. hurrah.
first pass at realigning menu options to cope with variable-width fonts. still need to do pure-text items.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4514 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-10-29 17:38:22 +00:00
parent 38305b4f06
commit fb86222fc7
94 changed files with 4766 additions and 2413 deletions

View File

@ -71,28 +71,6 @@ qboolean Cam_DrawViewModel(playerview_t *pv)
}
}
// returns true if we should draw this player, we don't if we are chase camming
qboolean Cam_DrawEntity(playerview_t *pv, int entitykey)
{
// if (!entitykey)
return true;
// if (playernum == cl.playernum[pnum])
// return false;
if (cl.spectator)
{
if (pv->cam_auto && pv->cam_locked && (cl_chasecam.value||scr_chatmode==2) &&
pv->cam_spec_track+1 == entitykey && r_secondaryview != 2)
return false;
}
else
{
if (selfcam == 1 && !r_refdef.externalview)
if (entitykey == pv->viewentity)
return false;
}
return true;
}
int Cam_TrackNum(playerview_t *pv)
{
if (!pv->cam_auto)
@ -136,7 +114,7 @@ void Cam_Lock(playerview_t *pv, int playernum)
Sbar_Changed();
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
}
@ -152,7 +130,7 @@ trace_t Cam_DoTrace(vec3_t vec1, vec3_t vec2)
#endif
VectorCopy (vec1, pmove.origin);
return PM_PlayerTrace(pmove.origin, vec2);
return PM_PlayerTrace(pmove.origin, vec2, MASK_PLAYERSOLID);
}
extern vec3_t player_mins;
@ -327,7 +305,7 @@ static void Cam_CheckHighTarget(playerview_t *pv)
playerview_t *spv;
j = -1;
for (i = 0, max = -9999; i < MAX_CLIENTS; i++)
for (i = 0, max = -9999; i < cl.allocated_client_slots; i++)
{
s = &cl.players[i];
if (s->name[0] && !s->spectator && s->frags > max)
@ -536,7 +514,7 @@ void Cam_TrackCrosshairedPlayer(playerview_t *pv)
player = frame->playerstate + pv->playernum;
VectorCopy(player->origin, selforg);
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
player = frame->playerstate + i;
VectorSubtract(player->origin, selforg, dir);

View File

@ -24,8 +24,8 @@ extern int mod_numknown;
#define VM_FROMMHANDLE(a) ((a&&((unsigned int)a)<=mod_numknown)?mod_known+a-1:NULL)
#define VM_TOMHANDLE(a) (a?a-mod_known+1:0)
#define VM_FROMSHANDLE(a) (a?r_shaders+a-1:NULL)
#define VM_TOSHANDLE(a) (a?a-r_shaders+1:0)
#define VM_FROMSHANDLE(a) (a?r_shaders[a-1]:NULL)
#define VM_TOSHANDLE(a) (a?a->id+1:0)
extern model_t box_model;
@ -859,8 +859,15 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
{
float *org = VM_POINTER(arg[1]);
vec3_t *axis = VM_POINTER(arg[2]);
int inwater = VM_LONG(arg[3]);
S_UpdateListener(org, axis[0], axis[1], axis[2]);
r_refdef.audio.defaulted = false;
//r_refdef.audio.entity = VM_LONG(arg[0]);
VectorCopy(org, r_refdef.audio.origin);
VectorCopy(axis[0], r_refdef.audio.forward);
VectorCopy(axis[1], r_refdef.audio.right);
VectorCopy(axis[2], r_refdef.audio.up);
r_refdef.audio.inwater = inwater;
}
break;

View File

@ -664,8 +664,8 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *
{
news->light[0] = MSG_ReadShort();
news->light[1] = MSG_ReadShort();
news->light[1] = MSG_ReadShort();
news->light[1] = MSG_ReadShort();
news->light[2] = MSG_ReadShort();
news->light[3] = MSG_ReadShort();
news->lightstyle = MSG_ReadByte();
news->lightpflags = MSG_ReadByte();
}
@ -1183,12 +1183,7 @@ void DP5_ParseDelta(entity_state_t *s)
int num;
num = s->number;
*s = nullentitystate;
s->trans = 255;
s->scale = 16;
s->number = num;
s->colormod[0] = (256)/8;
s->colormod[1] = (256)/8;
s->colormod[2] = (256)/8;
s->solid = ES_SOLID_BSP;
// s->active = true;
}
@ -3245,11 +3240,12 @@ void CL_LinkPacketEntities (void)
dl = CL_NewDlight(state->number, ent->origin, state->light[3]?state->light[3]:350, 0.1, colour[0], colour[1], colour[2]);
dl->corona = (state->lightpflags & PFLAGS_CORONA)?1:0;
dl->coronascale = 0.25;
dl->style = state->lightstyle;
dl->flags &= ~LFLAG_FLASHBLEND;
dl->flags |= (state->lightpflags & PFLAGS_NOSHADOW)?LFLAG_NOSHADOWS:0;
if (state->skinnum)
{
VectorCopy(angles, ent->angles);
VectorCopy(ent->angles, angles);
angles[0]*=-1; //pflags matches alias models.
AngleVectors(angles, dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
@ -4207,7 +4203,7 @@ void CL_LinkPlayers (void)
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
predictplayers = false;
for (j=0, info=cl.players, state=frame->playerstate ; j < MAX_CLIENTS
for (j=0, info=cl.players, state=frame->playerstate ; j < cl.allocated_client_slots
; j++, info++, state++)
{
nametagseen[j] = false;
@ -4742,7 +4738,7 @@ void CL_SetUpPlayerPrediction(qboolean dopred)
frame = &cl.inframes[cl.parsecount&UPDATE_MASK];
for (j=0, pplayer = predicted_players, state=frame->playerstate;
j < MAX_CLIENTS;
j < cl.allocated_client_slots;
j++, pplayer++, state++)
{
@ -4826,7 +4822,7 @@ void CL_SetSolidPlayers (void)
if (pmove.numphysent == MAX_PHYSENTS) //too many.
return;
for (j=0, pplayer = predicted_players; j < MAX_CLIENTS; j++, pplayer++)
for (j=0, pplayer = predicted_players; j < cl.allocated_client_slots; j++, pplayer++)
{
if (!pplayer->active)
continue; // not present this frame

View File

@ -37,7 +37,7 @@ int Player_IdtoSlot (int id)
{
int j;
for (j = 0; j < MAX_CLIENTS; j++)
for (j = 0; j < cl.allocated_client_slots; j++)
{
if (cl.players[j].name[0] && cl.players[j].userid == id)
return j;
@ -49,7 +49,7 @@ int Player_StringtoSlot(char *arg)
{
int i, slot;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (cl.players[i].name[0] && !strncmp(arg, cl.players[i].name, MAX_SCOREBOARDNAME - 1))
return i;
@ -70,7 +70,7 @@ int Player_NametoSlot(char *name)
{
int i;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (cl.players[i].name[0] && !strncmp(cl.players[i].name, name, MAX_SCOREBOARDNAME - 1))
return i;
@ -80,7 +80,7 @@ int Player_NametoSlot(char *name)
int Player_SlottoId (int slot)
{
return (slot >= 0 && slot < MAX_CLIENTS && cl.players[slot].name[0]) ? cl.players[slot].userid : -1;
return (slot >= 0 && slot < cl.allocated_client_slots && cl.players[slot].name[0]) ? cl.players[slot].userid : -1;
}
char *Player_MyName (void)
@ -128,7 +128,7 @@ static void Display_Ignorelist(void)
x = 0;
foundone = false;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (cl.players[i].name[0] && cl.players[i].ignored)
{
@ -147,7 +147,7 @@ static void Display_Ignorelist(void)
x = 0;
foundone = false;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (cl.players[i].name[0] && cl.players[i].ignored)
{
@ -410,7 +410,7 @@ static void Ignoreteam_f(void)
return;
}
arg = Cmd_Argv(1);
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (cl.players[i].name[0] && !cl.players[i].spectator && !strcmp(arg, cl.players[i].team))
{
@ -476,7 +476,7 @@ static void UnignoreAll_f (void)
Con_Printf("%s : no arguments expected\n", Cmd_Argv(0));
return;
}
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
Ignorelist_Del(i);
Con_Printf("User ignore list cleared\n");
}

View File

@ -300,7 +300,7 @@ void CL_MakeActive(char *gamename)
SCR_EndLoadingPlaque();
Mod_Flush(false);
Mod_Purge(MP_MAPCHANGED);
TP_ExecTrigger("f_spawn");
}
@ -3740,6 +3740,12 @@ void Host_DoRunFile(hrf_t *f)
return;
}
if (f->flags & HRF_MANIFEST)
{
Host_DoRunFile(f);
return;
}
VFS_SEEK(f->srcfile, 0);
f->dstfile = FS_OpenVFS(qname, "rb", FS_GAME);
@ -4042,7 +4048,15 @@ double Host_Frame (double time)
if (cls.state == ca_onserver && cl.validsequence && cl.worldmodel)
{ // first update is the final signon stage
CL_MakeActive("QuakeWorld");
if (cls.protocol == CP_NETQUAKE)
{
//nq can send 'frames' without any entities before we're on the server, leading to short periods where the local player's position is not known. this is bad. so be more cautious with nq. this might break csqc.
CL_TransitionEntities();
if (cl.currentpackentities->num_entities)
CL_MakeActive("Quake");
}
else
CL_MakeActive("QuakeWorld");
}
}
CL_AllowIndependantSendCmd(true);
@ -4070,6 +4084,13 @@ double Host_Frame (double time)
if (host_speeds.ival)
time1 = Sys_DoubleTime ();
r_refdef.audio.defaulted = true;
VectorClear(r_refdef.audio.origin);
VectorSet(r_refdef.audio.forward, 1, 0, 0);
VectorSet(r_refdef.audio.right, 0, 1, 0);
VectorSet(r_refdef.audio.up, 0, 0, 1);
r_refdef.audio.inwater = false;
if (SCR_UpdateScreen && !vid.isminimized)
{
extern mleaf_t *r_viewleaf;
@ -4081,30 +4102,16 @@ double Host_Frame (double time)
scr_chatmode = 0;
SCR_UpdateScreen ();
if (cls.state >= ca_active && r_viewleaf)
S_SetUnderWater(r_viewleaf->contents <= Q1CONTENTS_WATER);
else
S_SetUnderWater(false);
}
if (host_speeds.ival)
time2 = Sys_DoubleTime ();
// update audio
#ifdef CSQC_DAT
if (!CSQC_SettingListener())
#endif
{
if (cls.state == ca_active)
{
if (cls.protocol != CP_QUAKE3)
S_UpdateListener (r_origin, vpn, vright, vup);
}
else
S_UpdateListener (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
S_UpdateListener (r_refdef.audio.origin, r_refdef.audio.forward, r_refdef.audio.right, r_refdef.audio.up);
S_SetUnderWater(r_refdef.audio.inwater);
S_Update ();
}
S_Update ();
CDAudio_Update();
@ -4278,9 +4285,11 @@ void CL_ExecInitialConfigs(char *resetcommand)
int qrc, hrc, def;
Cbuf_AddText("cl_warncmd 0\n", RESTRICT_LOCAL);
Cbuf_AddText("unbindall", RESTRICT_LOCAL);
Cbuf_AddText("cvarreset *", RESTRICT_LOCAL);
Cbuf_AddText("unbindall\n", RESTRICT_LOCAL);
Cbuf_AddText("cvar_purgedefaults\n", RESTRICT_LOCAL); //reset cvar defaults to their engine-specified values. the tail end of 'exec default.cfg' will update non-cheat defaults to mod-specified values.
Cbuf_AddText("cvarreset *\n", RESTRICT_LOCAL); //reset all cvars to their current (engine) defaults
Cbuf_AddText(resetcommand, RESTRICT_LOCAL);
Cbuf_AddText("\n", RESTRICT_LOCAL);
//who should we imitate?
qrc = COM_FDepthFile("quake.rc", true); //q1
@ -4293,7 +4302,7 @@ void CL_ExecInitialConfigs(char *resetcommand)
Cbuf_AddText ("exec hexen.rc\n", RESTRICT_LOCAL);
else
{ //they didn't give us an rc file!
Cbuf_AddText ("bind ~ toggleconsole\n", RESTRICT_LOCAL); //we expect default.cfg to not exist. :(
Cbuf_AddText ("bind ~ toggleconsole\n", RESTRICT_LOCAL); //in case default.cfg does not exist. :(
Cbuf_AddText ("exec default.cfg\n", RESTRICT_LOCAL);
if (COM_FCheckExists ("config.cfg"))
Cbuf_AddText ("exec config.cfg\n", RESTRICT_LOCAL);
@ -4404,6 +4413,7 @@ void Host_Init (quakeparms_t *parms)
NET_InitClient ();
Netchan_Init ();
Renderer_Init();
Mod_Init(true);
// W_LoadWadFile ("gfx.wad");
Key_Init ();
@ -4502,6 +4512,7 @@ void Host_Shutdown(void)
CL_FreeDlights();
CL_FreeVisEdicts();
M_Shutdown();
Mod_Shutdown(true);
#ifndef CLIENTONLY
SV_Shutdown();
#else

View File

@ -11,29 +11,28 @@
//despite not supporting nq or q2, we still load them. We just filter them. This is to make sure we properly write the listing files.
enum {
enum mastertype_e
{
MT_BAD, //this would be an error
MT_MASTERHTTPNQ, //an http/ftp based master server with NQ servers
MT_MASTERHTTPQW,//an http/ftp based master server with QW servers
MT_MASTERHTTPJSON,//quakeone's server listing
MT_BCASTQW, //-1status
MT_BCASTQ2, //-1status
MT_BCASTQ3,
MT_BCASTNQ, //see code
MT_BCASTDP,
MT_SINGLEQW, //-1status
MT_SINGLEQ2, //-1status
MT_SINGLEQ3,
MT_SINGLENQ, //see code.
MT_SINGLEDP,
MT_MASTERQW, //c\n\0
MT_MASTERQ2, //query
MT_MASTERQ3,
MT_MASTERDP //-1getservers %s 3 empty full\x0A
MT_MASTERHTTPJSON,
MT_MASTERHTTP,
MT_MASTERUDP,
MT_BCAST,
MT_SINGLE,
};
enum masterprotocol_e
{
MP_UNSPECIFIED,
MP_QW,
MP_Q2,
MP_Q3,
MP_NQ,
MP_DP
};
typedef enum{
typedef enum
{
SLKEY_PING,
SLKEY_MAP,
SLKEY_NAME,
@ -60,7 +59,8 @@ typedef enum{
SLKEY_CUSTOM
} hostcachekey_t;
typedef enum {
typedef enum
{
SLIST_TEST_CONTAINS,
SLIST_TEST_NOTCONTAIN,
SLIST_TEST_LESSEQUAL,
@ -75,12 +75,14 @@ typedef enum {
//contains info about a server in greater detail. Could be too mem intensive.
typedef struct serverdetailedinfo_s {
typedef struct serverdetailedinfo_s
{
char info[MAX_SERVERINFO_STRING];
int numplayers;
struct {
struct
{
int userid;
int frags;
float time;
@ -93,7 +95,8 @@ typedef struct serverdetailedinfo_s {
} serverdetailedinfo_t;
//hold minimum info.
typedef struct serverinfo_s {
typedef struct serverinfo_s
{
char name[64]; //hostname.
netadr_t adr;
@ -127,18 +130,20 @@ typedef struct serverinfo_s {
struct serverinfo_s *next;
} serverinfo_t;
typedef struct master_s{
typedef struct master_s
{
struct master_s *next;
netadr_t adr;
char *address; //text based address (http servers)
struct dl_download *dl;
int type;
int servertype; //filled in for http servers
qbyte mastertype;
qbyte protocoltype;
int sends; /*needs to resend?*/
char name[1];
} master_t;
extern struct selectedserver_s {
extern struct selectedserver_s
{
qboolean inuse;
netadr_t adr;
@ -147,7 +152,8 @@ extern struct selectedserver_s {
int linenum;
} selectedserver;
typedef struct player_s {
typedef struct player_s
{
char name[16];
int frags;
int colour;
@ -167,7 +173,7 @@ void Master_SetupSockets(void);
void CL_QueryServers(void);
int Master_CheckPollSockets(void);
void MasterInfo_Shutdown(void);
void MasterInfo_Request(master_t *mast, qboolean evenifwedonthavethefiles);
void MasterInfo_Request(master_t *mast);
serverinfo_t *Master_InfoForServer (netadr_t *addr);
serverinfo_t *Master_InfoForNum (int num);
unsigned int Master_TotalCount(void);

View File

@ -4422,7 +4422,7 @@ void CL_MuzzleFlash (int destsplit)
if (s1->number == i)
{
dl = CL_AllocDlight (-i);
dl = CL_AllocDlight (i);
VectorCopy (s1->origin, dl->origin);
AngleVectors(s1->angles, dl->axis[0], dl->axis[1], dl->axis[2]);
break;
@ -4430,7 +4430,7 @@ void CL_MuzzleFlash (int destsplit)
}
if (pnum==pack->num_entities)
{ //that ent number doesn't exist, go for a player with that number
if ((unsigned)(i) <= MAX_CLIENTS && i > 0)
if ((unsigned)(i) <= cl.allocated_client_slots && i > 0)
{
pl = &cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[i-1];
@ -4449,14 +4449,15 @@ void CL_MuzzleFlash (int destsplit)
dl->radius = 200 + (rand()&31);
dl->minlight = 32;
dl->die = cl.time + 0.1334;
dl->color[0] = 1.0;
dl->color[1] = 0.4;
dl->color[2] = 0.2;
dl->die = cl.time + 0.5;
dl->color[0] = 1.3;
dl->color[1] = 0.9;
dl->color[2] = 0.5;
dl->channelfade[0] = 1.5;
dl->channelfade[1] = 0.75;
dl->channelfade[2] = 0.375;
dl->decay = 500;
}
#ifdef Q2CLIENT
@ -5075,7 +5076,7 @@ void CL_PrintStandardMessage(char *msg, int printlevel)
fullmessage[0] = 0;
// search for player names in message
for (i = 0, p = cl.players; i < MAX_CLIENTS; p++, i++)
for (i = 0, p = cl.players; i < cl.allocated_client_slots; p++, i++)
{
char *v;
char *name;
@ -6162,16 +6163,16 @@ qboolean CLNQ_ParseNQPrints(char *s)
return false;
*s = 0;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (!strcmp(start, cl.players[i].name))
break;
}
if (i == MAX_CLIENTS)
if (i == cl.allocated_client_slots)
{
}
if (i != MAX_CLIENTS)
if (i != cl.allocated_client_slots)
{
cl.players[i].ping = atoi(pingstart);
}
@ -6520,7 +6521,7 @@ void CLNQ_ParseServerMessage (void)
int a;
i = MSG_ReadByte ();
a = MSG_ReadByte ();
if (i < MAX_CLIENTS)
if (i < cl.allocated_client_slots)
{
cl.players[i].rtopcolor = a&0x0f;
cl.players[i].rbottomcolor = (a&0xf0)>>4;

View File

@ -614,7 +614,7 @@ void CL_CalcClientTime(void)
if (oldst == 0)
{
int i;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
cl.players[i].entertime += cl.servertime;
}

View File

@ -285,8 +285,8 @@ extern model_t mod_known[];
#define VM_FROMMHANDLE(a) (a?mod_known+a-1:NULL)
#define VM_TOMHANDLE(a) (a?a-mod_known+1:0)
#define VM_FROMSHANDLE(a) (a?r_shaders+a-1:NULL)
#define VM_TOSHANDLE(a) (a?a-r_shaders+1:0)
#define VM_FROMSHANDLE(a) (a?r_shaders[a-1]:NULL)
#define VM_TOSHANDLE(a) (a?a->id+1:0)
struct q3refEntity_s {

View File

@ -1160,7 +1160,6 @@ qboolean CSQC_MousePosition(float xabs, float yabs, int devid);
qboolean CSQC_Accelerometer(float x, float y, float z);
int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod);
void CSQC_ParseEntities(void);
qboolean CSQC_SettingListener(void);
qboolean CSQC_DeltaPlayer(int playernum, player_state_t *state);
void CSQC_DeltaStart(float time);
@ -1188,7 +1187,6 @@ void CL_CalcClientTime(void);
// cl_cam.c
//
qboolean Cam_DrawViewModel(playerview_t *pv);
qboolean Cam_DrawEntity(playerview_t *pv, int entitykey);
int Cam_TrackNum(playerview_t *pv);
void Cam_Unlock(playerview_t *pv);
void Cam_Lock(playerview_t *pv, int playernum);

View File

@ -510,7 +510,7 @@ static int Stats_ExtractName(char **line)
int ml = 0;
int l;
bm = -1;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (!qm_strcmp(cl.players[i].name, *line))
{

View File

@ -2173,12 +2173,8 @@ void BoostGamma(qbyte *rgba, int width, int height)
#if defined(GLQUAKE) || defined(D3DQUAKE)
#ifdef DDS
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
@ -2186,6 +2182,7 @@ void BoostGamma(qbyte *rgba, int width, int height)
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif
#ifdef IMAGEFMT_DDS
typedef struct {
unsigned int dwSize;
unsigned int dwFlags;
@ -2209,7 +2206,7 @@ typedef struct {
} ddsheader;
texid_tf GL_LoadTextureDDS(char *iname, unsigned char *buffer, int filesize)
texid_tf GL_ReadTextureDDS(char *iname, unsigned char *buffer, int filesize)
{
extern int gl_filter_min;
extern int gl_filter_max;
@ -2223,7 +2220,7 @@ texid_tf GL_LoadTextureDDS(char *iname, unsigned char *buffer, int filesize)
int divsize, blocksize;
ddsheader fmtheader;
if (*(int*)buffer != *(int*)"DDS ")
if (*(int*)buffer != *(int*)"DDS " || qrenderer != QR_OPENGL)
return r_nulltex;
buffer+=4;
@ -2302,6 +2299,158 @@ texid_tf GL_LoadTextureDDS(char *iname, unsigned char *buffer, int filesize)
}
#endif
#ifdef IMAGEFMT_BLP
texid_tf GL_ReadBLPFile(char *iname, unsigned char *buffer, int filesize)
{
extern int gl_filter_min;
extern int gl_filter_max;
//FIXME: cba with endian.
int miplevel;
int w, h, i;
struct blp_s
{
char blp2[4];
int type;
qbyte encoding;
qbyte alphadepth;
qbyte alphaencoding;
qbyte hasmips;
unsigned int xres;
unsigned int yres;
unsigned int mipoffset[16];
unsigned int mipsize[16];
unsigned int palette[256];
} *blp;
unsigned int *tmpmem = NULL;
unsigned char *in;
unsigned int inlen;
texid_tf texnum;
blp = (void*)buffer;
if (memcmp(blp->blp2, "BLP2", 4) || blp->type != 1 || qrenderer != QR_OPENGL)
return r_nulltex;
w = blp->xres;
h = blp->yres;
texnum = GL_AllocNewTexture(iname, w, h, 0);
GL_MTBind(0, GL_TEXTURE_2D, texnum);
for (miplevel = 0; ; )
{
//if we ran out of mips to load, give up.
if (miplevel == 16 || !blp->mipoffset[miplevel] || !blp->mipsize[miplevel] || blp->mipoffset[miplevel]+blp->mipsize[miplevel] > filesize)
{
//if we got at least one mip, cap the mips. might help save some ram? naaah...
//if this is the first mip, well, its completely fucked.
if (miplevel--)
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, miplevel);
break;
}
in = buffer + blp->mipoffset[miplevel];
inlen = blp->mipsize[miplevel];
if (blp->encoding == 2)
{
int type;
int blocksize;
//dxt compression
switch(blp->alphaencoding)
{
default:
case 0: //dxt1
if (blp->alphadepth)
type = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
else
type = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
blocksize = 8;
break;
case 1: //dxt2/3
type = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
blocksize = 16;
break;
case 7: //dxt4/5
type = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
blocksize = 16;
break;
}
if (inlen != ((w+3)/4) * ((h+3)/4) * blocksize)
{
Con_Printf("%s: mip level %i does not contain the correct amount of data\n", iname, miplevel);
if (miplevel--)
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, miplevel);
break;
}
qglCompressedTexImage2DARB(GL_TEXTURE_2D, miplevel, type, w, h, 0, inlen, in);
}
else
{
if (inlen != w*h+((w*h*blp->alphadepth+7)>>3))
{
Con_Printf("%s: mip level %i does not contain the correct amount of data\n", iname, miplevel);
if (miplevel--)
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, miplevel);
break;
}
if (!tmpmem)
tmpmem = malloc(4*w*h);
//8bit palette index
for (i = 0; i < w*h; i++)
tmpmem[i] = blp->palette[*in++] | 0xff000000;
switch(blp->alphadepth)
{
case 0:
//BGRX palette, 8bit
break;
case 1:
//BGRX palette, 8bit
//1bit trailing alpha
for (i = 0; i < w*h; i++)
tmpmem[i] = (tmpmem[i] & 0xffffff) | (*in++?0xff000000:0);
break;
case 4:
//BGRX palette, 8bit
//4bit trailing alpha
for (i = 0; i < w*h; i++)
tmpmem[i] = (tmpmem[i] & 0xffffff) | (*in++*0x11000000);
break;
case 8:
//BGRX palette, 8bit
//8bit trailing alpha
for (i = 0; i < w*h; i++)
tmpmem[i] = (tmpmem[i] & 0xffffff) | (*in++<<24);
break;
}
qglTexImage2D(GL_TEXTURE_2D, miplevel, GL_RGBA, w, h, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, tmpmem);
}
miplevel++;
if ((w <= 1 && h <= 1) || !blp->hasmips)
break;
w = (w+1)>>1;
h = (h+1)>>1;
}
if (tmpmem)
free(tmpmem);
if (miplevel>1)
{
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
else
{
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
return texnum;
}
#endif
//returns r8g8b8a8
qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, qboolean *hasalpha, char *fname)
{
@ -2344,6 +2493,63 @@ qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, qboolean
return NULL;
}
static void *R_FlipImage32(void *in, int *inoutwidth, int *inoutheight, qboolean flipx, qboolean flipy, qboolean flipd)
{
int x, y;
unsigned int *in32, *inr, *out32;
void *out;
int inwidth = *inoutwidth;
int inheight = *inoutheight;
int rowstride = inwidth;
int colstride = 1;
//simply return if no operation
if (!flipx && !flipy && !flipd)
return in;
inr = in;
out32 = out = BZ_Malloc(inwidth*inheight*4);
if (flipy)
{
inr += inwidth*inheight-inwidth;//start on the bottom row
rowstride *= -1; //and we need to move up instead
}
if (flipx)
{
colstride *= -1; //move backwards
inr += inwidth-1; //start at the end of the row
}
if (flipd)
{
//switch the dimensions
int tmp = inwidth;
inwidth = inheight;
inheight = tmp;
//make sure the caller gets the new dimensions
*inoutwidth = inwidth;
*inoutheight = inheight;
//switch the strides
tmp = colstride;
colstride = rowstride;
rowstride = tmp;
}
//rows->rows, columns->columns
for (y = 0; y < inheight; y++)
{
in32 = inr; //reset the input after each row, so we have truely independant row+column strides
inr += rowstride;
for (x = 0; x < inheight; x++)
{
*out32++ = *in32;
in32 += colstride;
}
}
BZ_Free(in);
return out;
}
static struct
{
char *name;
@ -2359,7 +2565,10 @@ static struct
{".png", 1}, //pngs, fairly common, but slow
#endif
{".tga", 1}, //fairly fast to load
#ifdef DDS
#ifdef IMAGEFMT_BLP
{".blp", 1}, //blizzard picture, for the luls
#endif
#ifdef IMAGEFMT_DDS
{".dds", 1}, //compressed or something
#endif
{"", 1} //someone forgot an extension
@ -2433,11 +2642,32 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags)
if ((flags & IF_TEXTYPE) == IF_CUBEMAP)
{
int j;
char *suf[] =
static struct
{
"rt", "lf", "ft", "bk", "up", "dn", //FIXME: This is inverted and thus wrong
"px", "nx", "py", "ny", "pz", "nz",
"posx", "negx", "posy", "negy", "posz", "negz"
char *suffix;
qboolean flipx, flipy, flipd;
} cmscheme[] =
{
{"rt", true, false, true},
{"lf", false, true, true},
{"ft", true, true, false},
{"bk", false, false, false},
{"up", true, false, true},
{"dn", true, false, true},
{"px", false, false, false},
{"nx", false, false, false},
{"py", false, false, false},
{"ny", false, false, false},
{"pz", false, false, false},
{"nz", false, false, false},
{"posx", false, false, false},
{"negx", false, false, false},
{"posy", false, false, false},
{"negy", false, false, false},
{"posz", false, false, false},
{"negz", false, false, false}
};
flags |= IF_REPLACE;
@ -2451,9 +2681,9 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags)
continue;
buf = NULL;
for (j = 0; j < sizeof(suf)/sizeof(suf[0])/6; j++)
for (j = 0; j < sizeof(cmscheme)/sizeof(cmscheme[0])/6; j++)
{
snprintf(fname, sizeof(fname)-1, "%s%s%s", nicename, suf[i + 6*j], tex_extensions[e].name);
snprintf(fname, sizeof(fname)-1, "%s%s%s", nicename, cmscheme[i + 6*j].suffix, tex_extensions[e].name);
buf = COM_LoadFile (fname, 5);
if (buf)
break;
@ -2467,6 +2697,7 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags)
extern cvar_t vid_hardwaregamma;
if (!(flags&IF_NOGAMMA) && !vid_hardwaregamma.value)
BoostGamma(data, image_width, image_height);
data = R_FlipImage32(data, &image_width, &image_height, cmscheme[i + 6*j].flipx, cmscheme[i + 6*j].flipy, cmscheme[i + 6*j].flipd);
tex = R_LoadTexture32 (name, image_width, image_height, data, (flags | IF_REPLACE) + (i << IF_TEXTYPESHIFT));
BZ_Free(data);
@ -2496,11 +2727,11 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags)
return tex;
}
#ifdef DDS
#ifdef IMAGEFMT_DDS
snprintf(fname, sizeof(fname)-1, "dds/%s.dds", nicename); /*should be safe if its null*/
if ((buf = COM_LoadFile (fname, 5)))
{
tex = GL_LoadTextureDDS(name, buf, com_filesize);
tex = GL_ReadTextureDDS(name, buf, com_filesize);
if (TEXVALID(tex))
{
BZ_Free(buf);
@ -2510,7 +2741,7 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags)
}
#endif
if (strchr(name, '/')) //never look in a root dir for the pic
if (strchr(name, '/') || strchr(name, '\\')) //never look in a root dir for the pic
i = 0;
else
i = 1;
@ -2540,14 +2771,26 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags)
TRACE(("dbg: Mod_LoadHiResTexture: trying %s\n", fname));
if ((buf = COM_LoadFile (fname, 5)))
{
#ifdef DDS
tex = GL_LoadTextureDDS(name, buf, com_filesize);
#ifdef IMAGEFMT_DDS
tex = GL_ReadTextureDDS(name, buf, com_filesize);
if (TEXVALID(tex))
{
BZ_Free(buf);
return tex;
}
#endif
#ifdef IMAGEFMT_BLP
if (buf[0] == 'B' && buf[1] == 'L' && buf[2] == 'P' && buf[3] == '2')
{
tex = GL_ReadBLPFile(name, buf, com_filesize);
if (TEXVALID(tex))
{
BZ_Free(buf);
return tex;
}
}
#endif
hasalpha = false;
if ((data = Read32BitImageFile(buf, com_filesize, &image_width, &image_height, &hasalpha, fname)))
{

View File

@ -473,11 +473,8 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
if (option->slider.text)
{
if (!menu->cursoritem && menu->selecteditem == option)
Draw_AltFunString(x, y, option->slider.text);
else
Draw_FunString(x, y, option->slider.text);
x += strlen(option->slider.text)*8+28;
Draw_FunStringWidth(x, y, option->slider.text, option->slider.textwidth, true, !menu->cursoritem && menu->selecteditem == option);
x += option->slider.textwidth + 3*8;
}
if (range < 0)
@ -522,11 +519,8 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
if (option->check.text)
{
if (!menu->cursoritem && menu->selecteditem == option)
Draw_AltFunString(x, y, option->check.text);
else
Draw_FunString(x, y, option->check.text);
x += strlen(option->check.text)*8+28;
Draw_FunStringWidth(x, y, option->check.text, option->check.textwidth, true, !menu->cursoritem && menu->selecteditem == option);
x += option->check.textwidth + 3*8;
}
#if 0
if (on)
@ -545,12 +539,8 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
int x = xpos+option->common.posx;
int y = ypos+option->common.posy;
//Fixme: variable width fonts
if (!menu->cursoritem && menu->selecteditem == option)
Draw_AltFunString(x, y, option->edit.caption);
else
Draw_FunString(x, y, option->edit.caption);
x+=strlen(option->edit.caption)*8+8;
Draw_FunStringWidth(x, y, option->edit.caption, option->edit.captionwidth, true, !menu->cursoritem && menu->selecteditem == option);
x += option->edit.captionwidth + 3*8;
if (option->edit.slim)
x += 8; // more space for cursor
else
@ -571,11 +561,9 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
int keys[2];
char *keyname;
if (!menu->cursoritem && menu->selecteditem == option)
Draw_AltFunString(x, y, option->bind.caption);
else
Draw_FunString(x, y, option->bind.caption);
x += strlen(option->bind.caption)*8+28;
Draw_FunStringWidth(x, y, option->bind.caption, option->bind.captionwidth, true, !menu->cursoritem && menu->selecteditem == option);
x += option->bind.captionwidth + 3*8;
{
extern cvar_t cl_forcesplitclient;
@ -609,11 +597,9 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
int x = xpos+option->common.posx;
int y = ypos+option->common.posy;
if (!menu->cursoritem && menu->selecteditem == option)
Draw_AltFunString(x, y, option->combo.caption);
else
Draw_FunString(x, y, option->combo.caption);
x += strlen(option->combo.caption)*8+24;
Draw_FunStringWidth(x, y, option->combo.caption, option->combo.captionwidth, true, !menu->cursoritem && menu->selecteditem == option);
x += option->combo.captionwidth + 3*8;
if (option->combo.numoptions)
{
if (!menu->cursoritem && menu->selecteditem == option)
@ -719,18 +705,19 @@ menutext_t *MC_AddRedText(menu_t *menu, int x, int y, const char *text, qboolean
return n;
}
menubind_t *MC_AddBind(menu_t *menu, int x, int y, const char *caption, char *command)
menubind_t *MC_AddBind(menu_t *menu, int cx, int bx, int y, const char *caption, char *command)
{
menubind_t *n = Z_Malloc(sizeof(menutext_t) + strlen(caption)+1 + strlen(command)+1);
n->common.type = mt_bind;
n->common.iszone = true;
n->common.posx = x;
n->common.posx = cx;
n->common.posy = y;
n->captionwidth = bx-cx;
n->caption = (char *)(n+1);
strcpy(n->caption, caption);
n->command = n->caption+strlen(n->caption)+1;
strcpy(n->command, command);
n->common.width = strlen(caption)*8 + 64;
n->common.width = n->captionwidth + 64;
n->common.height = 8;
n->common.next = menu->options;
@ -850,15 +837,20 @@ menupicture_t *MC_AddCursor(menu_t *menu, int x, int y)
return n;
}
menuedit_t *MC_AddEdit(menu_t *menu, int x, int y, char *text, char *def)
menuedit_t *MC_AddEdit(menu_t *menu, int cx, int ex, int y, char *text, char *def)
{
menuedit_t *n = Z_Malloc(sizeof(menuedit_t));
menuedit_t *n = Z_Malloc(sizeof(menuedit_t)+strlen(text)+1);
n->slim = false;
n->common.type = mt_edit;
n->common.iszone = true;
n->common.posx = x;
n->common.posx = cx;
n->common.posy = y;
n->common.width = ex-cx+(17)*8;
n->common.height = n->slim?8:16;
n->modified = true;
n->caption = text;
n->captionwidth = ex-cx;
n->caption = (char *)(n+1);
strcpy((char *)(n+1), text);
Q_strncpyz(n->text, def, sizeof(n->text));
n->common.next = menu->options;
@ -866,19 +858,21 @@ menuedit_t *MC_AddEdit(menu_t *menu, int x, int y, char *text, char *def)
return n;
}
menuedit_t *MC_AddEditCvar_Full(menu_t *menu, int x, int y, char *text, char *name, qboolean isslim)
menuedit_t *MC_AddEditCvar(menu_t *menu, int cx, int ex, int y, char *text, char *name, qboolean isslim)
{
menuedit_t *n = Z_Malloc(sizeof(menuedit_t)+strlen(text)+1);
cvar_t *cvar;
cvar = Cvar_Get(name, "", CVAR_USERCREATED|CVAR_ARCHIVE, NULL); //well, this is a menu/
n->slim = isslim;
n->common.type = mt_edit;
n->common.iszone = true;
n->common.posx = x;
n->common.posx = cx;
n->common.posy = y;
n->common.width = (strlen(text)+17)*8;
n->common.height = 8;
n->common.width = ex-cx+(17)*8;
n->common.height = n->slim?8:16;
n->common.tooltip = cvar->description;
n->modified = true;
n->captionwidth = ex-cx;
n->caption = (char *)(n+1);
strcpy((char *)(n+1), text);
n->cvar = cvar;
@ -889,21 +883,10 @@ menuedit_t *MC_AddEditCvar_Full(menu_t *menu, int x, int y, char *text, char *na
Q_strncpyz(n->text, cvar->string, sizeof(n->text));
n->common.next = menu->options;
n->slim = isslim;
menu->options = (menuoption_t *)n;
return n;
}
menuedit_t *MC_AddEditCvarSlim(menu_t *menu, int x, int y, char *text, char *name)
{
return MC_AddEditCvar_Full(menu, x, y, text, name, true);
}
menuedit_t *MC_AddEditCvar(menu_t *menu, int x, int y, char *text, char *name)
{
return MC_AddEditCvar_Full(menu, x, y, text, name, false);
}
menubox_t *MC_AddBox(menu_t *menu, int x, int y, int width, int height)
{
menubox_t *n = Z_Malloc(sizeof(menubox_t));
@ -934,15 +917,16 @@ menucustom_t *MC_AddCustom(menu_t *menu, int x, int y, void *dptr, int dint)
return n;
}
menucheck_t *MC_AddCheckBox(menu_t *menu, int x, int y, const char *text, cvar_t *var, int bits)
menucheck_t *MC_AddCheckBox(menu_t *menu, int tx, int cx, int y, const char *text, cvar_t *var, int bits)
{
menucheck_t *n = Z_Malloc(sizeof(menucheck_t)+strlen(text)+1);
n->common.type = mt_checkbox;
n->common.iszone = true;
n->common.posx = x;
n->common.posx = tx;
n->common.posy = y;
n->common.height = 8;
n->common.width = (strlen(text)+7)*8;
n->textwidth = cx - tx;
n->common.width = cx-tx + 7*8;
n->common.tooltip = var?var->description:NULL;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
@ -961,15 +945,16 @@ menucheck_t *MC_AddCheckBox(menu_t *menu, int x, int y, const char *text, cvar_t
menu->options = (menuoption_t *)n;
return n;
}
menucheck_t *MC_AddCheckBoxFunc(menu_t *menu, int x, int y, const char *text, qboolean (*func) (menucheck_t *option, menu_t *menu, chk_set_t set), int bits)
menucheck_t *MC_AddCheckBoxFunc(menu_t *menu, int tx, int cx, int y, const char *text, qboolean (*func) (menucheck_t *option, menu_t *menu, chk_set_t set), int bits)
{
menucheck_t *n = Z_Malloc(sizeof(menucheck_t)+strlen(text)+1);
n->common.type = mt_checkbox;
n->common.iszone = true;
n->common.posx = x;
n->common.posx = tx;
n->common.posy = y;
n->common.height = 8;
n->common.width = (strlen(text)+7)*8;
n->textwidth = cx - tx;
n->common.width = cx-tx + 7*8;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
n->func = func;
@ -981,17 +966,18 @@ menucheck_t *MC_AddCheckBoxFunc(menu_t *menu, int x, int y, const char *text, qb
}
//delta may be 0
menuslider_t *MC_AddSlider(menu_t *menu, int x, int y, const char *text, cvar_t *var, float min, float max, float delta)
menuslider_t *MC_AddSlider(menu_t *menu, int tx, int sx, int y, const char *text, cvar_t *var, float min, float max, float delta)
{
menuslider_t *n = Z_Malloc(sizeof(menuslider_t)+strlen(text)+1);
n->common.type = mt_slider;
n->common.iszone = true;
n->common.posx = x;
n->common.posx = tx;
n->common.posy = y;
n->common.height = 8;
n->common.width = (strlen(text)+SLIDER_RANGE+5)*8;
n->common.width = sx-tx + (SLIDER_RANGE+5)*8;
n->common.tooltip = var->description;
n->var = var;
n->textwidth = sx-tx;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
@ -1016,7 +1002,7 @@ menuslider_t *MC_AddSlider(menu_t *menu, int x, int y, const char *text, cvar_t
return n;
}
menucombo_t *MC_AddCombo(menu_t *menu, int x, int y, const char *caption, const char **ops, int initialvalue)
menucombo_t *MC_AddCombo(menu_t *menu, int tx, int cx, int y, const char *caption, const char **ops, int initialvalue)
{
int numopts;
int optlen;
@ -1046,10 +1032,11 @@ menucombo_t *MC_AddCombo(menu_t *menu, int x, int y, const char *caption, const
optbuf = (char*)(newops + numopts+1);
n->common.type = mt_combo;
n->common.iszone = true;
n->common.posx = x;
n->common.posx = tx;
n->common.posy = y;
n->common.height = 8;
n->common.width = strlen(caption)*8 + maxoptlen*8;
n->common.width = cx-tx + maxoptlen*8;
n->captionwidth = cx-tx;
n->caption = caption;
n->options = (const char **)newops;
@ -1074,7 +1061,7 @@ menucombo_t *MC_AddCombo(menu_t *menu, int x, int y, const char *caption, const
return n;
}
menucombo_t *MC_AddCvarCombo(menu_t *menu, int x, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values)
menucombo_t *MC_AddCvarCombo(menu_t *menu, int tx, int cx, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values)
{
int numopts;
int optlen;
@ -1108,11 +1095,12 @@ menucombo_t *MC_AddCvarCombo(menu_t *menu, int x, int y, const char *caption, cv
optbuf = (char*)(newvalues + numopts+1);
n->common.type = mt_combo;
n->common.iszone = true;
n->common.posx = x;
n->common.posx = tx;
n->common.posy = y;
n->common.height = 8;
n->common.width = strlen(caption)*8 + maxoptlen*8;
n->common.width = cx-tx + maxoptlen*8;
n->common.tooltip = cvar->description;
n->captionwidth = cx-tx;
strcpy(optbuf, caption);
n->caption = optbuf;
@ -2148,21 +2136,21 @@ int MC_AddBulk(struct menu_s *menu, menubulk_t *bulk, int xstart, int xtextend,
}
break;
case mt_checkbox:
control = (union menuoption_s *)MC_AddCheckBox(menu, x, y, bulk->text, bulk->cvar, bulk->flags);
control = (union menuoption_s *)MC_AddCheckBox(menu, xleft, xtextend, y, bulk->text, bulk->cvar, bulk->flags);
control->check.func = bulk->func;
break;
case mt_slider:
control = (union menuoption_s *)MC_AddSlider(menu, x, y, bulk->text, bulk->cvar, bulk->min, bulk->max, bulk->delta);
control = (union menuoption_s *)MC_AddSlider(menu, xleft, xtextend, y, bulk->text, bulk->cvar, bulk->min, bulk->max, bulk->delta);
break;
case mt_combo:
switch (bulk->variant)
{
default:
case 0: // cvar combo
control = (union menuoption_s *)MC_AddCvarCombo(menu, x, y, bulk->text, bulk->cvar, bulk->options, bulk->values);
control = (union menuoption_s *)MC_AddCvarCombo(menu, xleft, xtextend, y, bulk->text, bulk->cvar, bulk->options, bulk->values);
break;
case 1: // combo with return value
control = (union menuoption_s *)MC_AddCombo(menu, x, y, bulk->text, bulk->options, bulk->selectedoption);
control = (union menuoption_s *)MC_AddCombo(menu, xleft, xtextend, y, bulk->text, bulk->options, bulk->selectedoption);
break;
}
break;
@ -2172,11 +2160,11 @@ int MC_AddBulk(struct menu_s *menu, menubulk_t *bulk, int xstart, int xtextend,
default:
case 0:
y += 4;
control = (union menuoption_s *)MC_AddEditCvar(menu, x, y, bulk->text, bulk->cvarname);
control = (union menuoption_s *)MC_AddEditCvar(menu, xleft, xtextend, y, bulk->text, bulk->cvarname, false);
spacing += 4;
break;
case 1:
control = (union menuoption_s *)MC_AddEditCvarSlim(menu, x, y, bulk->text, bulk->cvarname);
control = (union menuoption_s *)MC_AddEditCvar(menu, xleft, xtextend, y, bulk->text, bulk->cvarname, true);
break;
}
break;

View File

@ -83,7 +83,7 @@ static void SL_DrawColumnTitle (int *x, int y, int xlen, int mx, char *str, qboo
R2D_ImageColours((sin(realtime*4.4)*0.25)+0.5, (sin(realtime*4.4)*0.25)+0.5, 0.08, 1.0);
R2D_FillBlock(xmin, y, xlen, 8);
}
Draw_FunStringWidth(xmin, y, str, xlen);
Draw_FunStringWidth(xmin, y, str, xlen, false, false);
if (x != NULL)
*x -= xlen + 8;
@ -232,7 +232,7 @@ static void SL_ServerDraw (int x, int y, menucustom_t *ths, menu_t *menu)
serverhighlight[(int)stype][2],
1.0);
}
else if (thisone == info->scrollpos + (mousecursor_y-16)/8 && mousecursor_x < x)
else if (thisone == info->scrollpos + (int)(mousecursor_y-16)/8 && mousecursor_x < x)
R2D_ImageColours((sin(realtime*4.4)*0.25)+0.5, (sin(realtime*4.4)*0.25)+0.5, 0.08, 1.0);
else if (selectedserver.inuse && NET_CompareAdr(&si->adr, &selectedserver.adr))
R2D_ImageColours(((sin(realtime*4.4)*0.25)+0.5) * 0.5, ((sin(realtime*4.4)*0.25)+0.5)*0.5, 0.08*0.5, 1.0);
@ -246,14 +246,14 @@ static void SL_ServerDraw (int x, int y, menucustom_t *ths, menu_t *menu)
}
R2D_FillBlock(0, y, ths->common.width, 8);
if (sb_showtimelimit.value) {Draw_FunStringWidth((x-3*8), y, va("%i", si->tl), 3*8); x-=4*8;}
if (sb_showfraglimit.value) {Draw_FunStringWidth((x-3*8), y, va("%i", si->fl), 3*8); x-=4*8;}
if (sb_showplayers.value) {Draw_FunStringWidth((x-5*8), y, va("%2i/%2i", si->players, si->maxplayers), 5*8); x-=6*8;}
if (sb_showmap.value) {Draw_FunStringWidth((x-8*8), y, si->map, 8*8); x-=9*8;}
if (sb_showgamedir.value) {Draw_FunStringWidth((x-8*8), y, si->gamedir, 8*8); x-=9*8;}
if (sb_showping.value) {Draw_FunStringWidth((x-3*8), y, va("%i", si->ping), 3*8); x-=4*8;}
if (sb_showaddress.value) {Draw_FunStringWidth((x-21*8), y, NET_AdrToString(adr, sizeof(adr), &si->adr), 21*8); x-=22*8;}
Draw_FunStringWidth(0, y, si->name, x);
if (sb_showtimelimit.value) {Draw_FunStringWidth((x-3*8), y, va("%i", si->tl), 3*8, false, false); x-=4*8;}
if (sb_showfraglimit.value) {Draw_FunStringWidth((x-3*8), y, va("%i", si->fl), 3*8, false, false); x-=4*8;}
if (sb_showplayers.value) {Draw_FunStringWidth((x-5*8), y, va("%2i/%2i", si->players, si->maxplayers), 5*8, false, false); x-=6*8;}
if (sb_showmap.value) {Draw_FunStringWidth((x-8*8), y, si->map, 8*8, false, false); x-=9*8;}
if (sb_showgamedir.value) {Draw_FunStringWidth((x-8*8), y, si->gamedir, 8*8, false, false); x-=9*8;}
if (sb_showping.value) {Draw_FunStringWidth((x-3*8), y, va("%i", si->ping), 3*8, false, false); x-=4*8;}
if (sb_showaddress.value) {Draw_FunStringWidth((x-21*8), y, NET_AdrToString(adr, sizeof(adr), &si->adr), 21*8, false, false); x-=22*8;}
Draw_FunStringWidth(0, y, si->name, x, false, false);
}
}
static qboolean SL_ServerKey (menucustom_t *ths, menu_t *menu, int key)
@ -414,9 +414,9 @@ static void SL_ServerPlayer (int x, int y, menucustom_t *ths, menu_t *menu)
R2D_FillBlock (x, y, 28, 4);
R2D_ImagePaletteColour (Sbar_ColorForMap(selectedserver.detail->players[i].botc), 1.0);
R2D_FillBlock (x, y+4, 28, 4);
Draw_FunStringWidth (x, y, va("%3i", selectedserver.detail->players[i].frags), 28);
Draw_FunStringWidth (x, y, va("%3i", selectedserver.detail->players[i].frags), 28, false, false);
Draw_FunStringWidth (x+28, y, selectedserver.detail->players[i].name, 12*8);
Draw_FunStringWidth (x+28, y, selectedserver.detail->players[i].name, 12*8, false, false);
}
}
}
@ -644,27 +644,27 @@ void M_Menu_ServerList2_f(void)
strcpy(info->refreshtext, "Refresh");
MC_AddCheckBox(menu, 0, vid.height - 64+8*1, "Ping ", &sb_showping, 1);
MC_AddCheckBox(menu, 0, vid.height - 64+8*2, "Address ", &sb_showaddress, 1);
MC_AddCheckBox(menu, 0, vid.height - 64+8*3, "Map ", &sb_showmap, 1);
MC_AddCheckBox(menu, 0, vid.height - 64+8*4, "Gamedir ", &sb_showgamedir, 1);
MC_AddCheckBox(menu, 0, vid.height - 64+8*5, "Players ", &sb_showplayers, 1);
MC_AddCheckBox(menu, 0, vid.height - 64+8*6, "Fraglimit", &sb_showfraglimit, 1);
MC_AddCheckBox(menu, 0, vid.height - 64+8*7, "Timelimit", &sb_showtimelimit, 1);
MC_AddCheckBox(menu, 0, 72, vid.height - 64+8*1, "Ping ", &sb_showping, 1);
MC_AddCheckBox(menu, 0, 72, vid.height - 64+8*2, "Address ", &sb_showaddress, 1);
MC_AddCheckBox(menu, 0, 72, vid.height - 64+8*3, "Map ", &sb_showmap, 1);
MC_AddCheckBox(menu, 0, 72, vid.height - 64+8*4, "Gamedir ", &sb_showgamedir, 1);
MC_AddCheckBox(menu, 0, 72, vid.height - 64+8*5, "Players ", &sb_showplayers, 1);
MC_AddCheckBox(menu, 0, 72, vid.height - 64+8*6, "Fraglimit", &sb_showfraglimit, 1);
MC_AddCheckBox(menu, 0, 72, vid.height - 64+8*7, "Timelimit", &sb_showtimelimit, 1);
#ifdef NQPROT
MC_AddCheckBoxFunc(menu, 128, vid.height - 64+8*1, "List NQ ", SL_ReFilter, 1);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*1, "List NQ ", SL_ReFilter, 1);
#endif
MC_AddCheckBoxFunc(menu, 128, vid.height - 64+8*2, "List QW ", SL_ReFilter, 2);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*2, "List QW ", SL_ReFilter, 2);
#ifdef Q2CLIENT
MC_AddCheckBoxFunc(menu, 128, vid.height - 64+8*3, "List Q2 ", SL_ReFilter, 3);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*3, "List Q2 ", SL_ReFilter, 3);
#endif
#ifdef Q3CLIENT
MC_AddCheckBoxFunc(menu, 128, vid.height - 64+8*4, "List Q3 ", SL_ReFilter, 4);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*4, "List Q3 ", SL_ReFilter, 4);
#endif
MC_AddCheckBoxFunc(menu, 128, vid.height - 64+8*5, "Only Favs ", SL_ReFilter, 5);
MC_AddCheckBoxFunc(menu, 128, vid.height - 64+8*6, "Hide Empty", SL_ReFilter, 6);
MC_AddCheckBoxFunc(menu, 128, vid.height - 64+8*7, "Hide Full ", SL_ReFilter, 7);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*5, "Only Favs ", SL_ReFilter, 5);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*6, "Hide Empty", SL_ReFilter, 6);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*7, "Hide Full ", SL_ReFilter, 7);
MC_AddCommand(menu, 64, 0, info->refreshtext, SL_DoRefresh);

View File

@ -353,8 +353,8 @@ void M_Menu_Setup_f (void)
MC_AddPicture(menu, 0, 173, 36, 42, "pics/m_main_logo");
menu->selecteditem = (menuoption_t*)
(info->nameedit = MC_AddEdit(menu, 64, 40, "Your name", name.string));
(info->modeledit = MC_AddCvarCombo(menu, 64, 72, "model", &skin, (const char **)modeloptions, (const char **)modeloptions));
(info->nameedit = MC_AddEdit(menu, 64, 160, 40, "Your name", name.string));
(info->modeledit = MC_AddCvarCombo(menu, 64, 160,72, "model", &skin, (const char **)modeloptions, (const char **)modeloptions));
info->modeledit->selectedoption = !strncmp(skin.string, "female", 6);
cu = MC_AddCustom(menu, 172-16, 88+16, NULL, 0);
cu->draw = MSetupQ2_TransDraw;
@ -401,8 +401,8 @@ void M_Menu_Setup_f (void)
// MC_AddPicture(menu, 72, 32, Draw_CachePic ("gfx/mp_menu.lmp") );
menu->selecteditem = (menuoption_t*)
(info->nameedit = MC_AddEdit(menu, 64, 40, "Your name", name.string));
(info->teamedit = MC_AddEdit(menu, 64, 56, "Your team", team.string));
(info->nameedit = MC_AddEdit(menu, 64, 160, 40, "Your name", name.string));
(info->teamedit = MC_AddEdit(menu, 64, 160, 56, "Your team", team.string));
if (mgt == MGT_HEXEN2)
{
static const char *classnames[] =
@ -415,10 +415,10 @@ void M_Menu_Setup_f (void)
NULL
};
cvar_t *pc = Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
(info->classedit = MC_AddCombo(menu, 64, 72, "Your class", (const char **)classnames, pc->ival-1));
(info->classedit = MC_AddCombo(menu, 64, 160, 72, "Your class", (const char **)classnames, pc->ival-1));
}
else
(info->skinedit = MC_AddEdit(menu, 64, 72, "Your skin", skin.string));
(info->skinedit = MC_AddEdit(menu, 64, 160, 72, "Your skin", skin.string));
ci = MC_AddCustom(menu, 172+32, 88, NULL, 0);
ci->draw = MSetup_TransDraw;
@ -600,7 +600,7 @@ void M_Menu_GameOptions_f (void)
menu->selecteditem = (menuoption_t*)
MC_AddCommand (menu, 64, y, " Start game", MultiBeginGame);y+=16;
info->hostnameedit = MC_AddEdit (menu, 64, y, " Hostname", name.string);y+=16;
info->hostnameedit = MC_AddEdit (menu, 64, 160, y, " Hostname", name.string);y+=16;
for (players = 0; players < sizeof(numplayeroptions)/ sizeof(numplayeroptions[0]); players++)
{
@ -608,22 +608,22 @@ void M_Menu_GameOptions_f (void)
break;
}
info->numplayers = MC_AddCombo (menu, 64, y, "Max players", (const char **)numplayeroptions, players);y+=8;
info->numplayers = MC_AddCombo (menu, 64, 160, y, "Max players", (const char **)numplayeroptions, players);y+=8;
info->deathmatch = MC_AddCombo (menu, 64, y, " Deathmatch", (const char **)deathmatchoptions, deathmatch.value);y+=8;
info->teamplay = MC_AddCombo (menu, 64, y, " Teamplay", (const char **)teamplayoptions, teamplay.value);y+=8;
info->skill = MC_AddCombo (menu, 64, y, " Skill", (const char **)skilloptions, skill.value);y+=8;
info->rundedicated = MC_AddCheckBox(menu, 64, y, " dedicated", NULL, 0);y+=8;
info->deathmatch = MC_AddCombo (menu, 64, 160, y, " Deathmatch", (const char **)deathmatchoptions, deathmatch.value);y+=8;
info->teamplay = MC_AddCombo (menu, 64, 160, y, " Teamplay", (const char **)teamplayoptions, teamplay.value);y+=8;
info->skill = MC_AddCombo (menu, 64, 160, y, " Skill", (const char **)skilloptions, skill.value);y+=8;
info->rundedicated = MC_AddCheckBox(menu, 64, 160, y, " dedicated", NULL, 0);y+=8;
y+=8;
info->timelimit = MC_AddCombo (menu, 64, y, " Time Limit", (const char **)timelimitoptions, timelimit.value/5);y+=8;
info->fraglimit = MC_AddCombo (menu, 64, y, " Frag Limit", (const char **)fraglimitoptions, fraglimit.value/10);y+=8;
info->timelimit = MC_AddCombo (menu, 64, 160, y, " Time Limit", (const char **)timelimitoptions, timelimit.value/5);y+=8;
info->fraglimit = MC_AddCombo (menu, 64, 160, y, " Frag Limit", (const char **)fraglimitoptions, fraglimit.value/10);y+=8;
y+=8;
MC_AddSlider (menu, 64-7*8, y, "Extra edict support", &pr_maxedicts, 512, 2047, 256);y+=8;
MC_AddSlider (menu, 64-7*8, 160, y, "Extra edict support", &pr_maxedicts, 512, 2047, 256);y+=8;
y+=8;
if (mgt == MGT_QUAKE2)
info->mapnameedit = MC_AddEdit (menu, 64, y, " map", "base1");
info->mapnameedit = MC_AddEdit (menu, 64, 160, y, " map", "base1");
else
info->mapnameedit = MC_AddEdit (menu, 64, y, " map", "start");
info->mapnameedit = MC_AddEdit (menu, 64, 160, y, " map", "start");
y += 16;
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 32, NULL, false);

View File

@ -290,7 +290,6 @@ struct audiomenuinfo *M_Menu_Audio_Setup(menu_t *menu)
return info;
}
menucombo_t *MC_AddCvarCombo(menu_t *menu, int x, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values);
void M_Menu_Audio_f (void)
{
int y;
@ -544,6 +543,7 @@ const char *presetexec[] =
"r_drawflame 0;"
"r_waterstyle 0;"
"r_lavastyle 0;"
"r_coronas 0;"
"r_shadow_realtime_dlight 0;"
"r_shadow_realtime_world 0;"
"r_glsl_offsetmapping 0;"
@ -567,7 +567,7 @@ const char *presetexec[] =
"r_lavastyle 1;"
"r_nolightdir 0;"
, // normal (faithful) options, with content replacement thrown in
, // normal (faithful) options, but with content replacement thrown in
#ifdef MINIMAL
"r_particlesystem classic;"
#else
@ -582,6 +582,7 @@ const char *presetexec[] =
"r_replacemodels \"md3 md2\";"
"r_waterwarp 1;"
"r_drawflame 1;"
"r_coronas 1;"
, // nice options
"r_stains 0.75;"
@ -1382,25 +1383,25 @@ void M_Menu_Singleplayer_Cheats_Quake (void)
MC_AddWhiteText(menu, 16, y, "<><E282AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ", false); y+=8;
y+=8;
#ifndef CLIENTONLY
info->skillcombo = MC_AddCombo(menu,16, y, " Difficulty", skilloptions, currentskill); y+=8;
info->mapcombo = MC_AddCombo(menu,16, y, " Map", mapoptions_q1, currentmap); y+=8;
MC_AddCheckBox(menu, 16, y, " Cheats", &sv_cheats,0); y+=8;
info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8;
info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions_q1, currentmap); y+=8;
MC_AddCheckBox(menu, 16, 170, y, "Cheats", &sv_cheats,0); y+=8;
#endif
#ifdef TEXTEDITOR
MC_AddCheckBox(menu, 16, y, " Debugger", &debugger, 0); y+=8;
MC_AddCheckBox(menu, 16, 170, y, "Debugger", &debugger, 0); y+=8;
#endif
MC_AddConsoleCommand(menu, 16, y, " Toggle Godmode", "god\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, " Toggle Flymode", "fly\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, " Toggle Noclip", "noclip\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, " Quad Damage", "impulse 255\n"); y+=8;
#ifndef CLIENTONLY
MC_AddSlider(menu, 16, y, " Gravity", &sv_gravity,0,800,25); y+=8;
MC_AddSlider(menu, 16, 170, y, "Gravity", &sv_gravity,0,800,25); y+=8;
#endif
MC_AddSlider(menu, 16, y, " Forward Speed", &cl_forwardspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, y, " Side Speed", &cl_sidespeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, y, " Back Speed", &cl_backspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Forward Speed", &cl_forwardspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Side Speed", &cl_sidespeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Back Speed", &cl_backspeed,0,1000,50); y+=8;
#ifndef CLIENTONLY
MC_AddSlider(menu, 16, y, " Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8;
#endif
MC_AddConsoleCommand(menu, 16, y, " Silver & Gold Keys", "impulse 13\nimpulse 14\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, "All Weapons & Items", "impulse 9\n"); y+=8;
@ -1496,20 +1497,20 @@ void M_Menu_Singleplayer_Cheats_Quake2 (void)
MC_AddWhiteText(menu, 16, y, "<><E282AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ", false); y+=8;
y+=8;
#ifndef CLIENTONLY
info->skillcombo = MC_AddCombo(menu,16, y, " Difficulty", skilloptions, currentskill); y+=8;
info->mapcombo = MC_AddCombo(menu,16, y, " Map", mapoptions_q2, currentmap); y+=8;
MC_AddCheckBox(menu, 16, y, " Cheats", &sv_cheats,0); y+=8;
info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8;
info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions_q2, currentmap); y+=8;
MC_AddCheckBox(menu, 16, 170, y, "Cheats", &sv_cheats,0); y+=8;
#endif
MC_AddConsoleCommand(menu, 16, y, " Toggle Godmode", "god\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, " Toggle Noclip", "noclip\n"); y+=8;
#ifndef CLIENTONLY
MC_AddSlider(menu, 16, y, " Gravity", &sv_gravity,0,850,25); y+=8;
MC_AddSlider(menu, 16, 170, y, "Gravity", &sv_gravity,0,850,25); y+=8;
#endif
MC_AddSlider(menu, 16, y, " Forward Speed", &cl_forwardspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, y, " Side Speed", &cl_sidespeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, y, " Back Speed", &cl_backspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Forward Speed", &cl_forwardspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Side Speed", &cl_sidespeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Back Speed", &cl_backspeed,0,1000,50); y+=8;
#ifndef CLIENTONLY
MC_AddSlider(menu, 16, y, " Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8;
#endif
MC_AddConsoleCommand(menu, 16, y, " Unlimited Ammo", "dmflags 8192\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, " Quad Damage", "give quad damage\n"); y+=8;
@ -1854,23 +1855,23 @@ void M_Menu_Singleplayer_Cheats_Hexen2 (void)
MC_AddWhiteText(menu, 16, y, "<><E282AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ", false); y+=8;
y+=8;
#ifndef CLIENTONLY
info->skillcombo = MC_AddCombo(menu,16, y, " Difficulty", skilloptions, currentskill); y+=8;
info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8;
#endif
info->mapcombo = MC_AddCombo(menu,16, y, " Map", mapoptions, currentmap); y+=8;
info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions, currentmap); y+=8;
#ifndef CLIENTONLY
MC_AddCheckBox(menu, 16, y, " Cheats", &sv_cheats,0); y+=8;
MC_AddCheckBox(menu, 16, 170, y, "Cheats", &sv_cheats,0); y+=8;
#endif
MC_AddConsoleCommand(menu, 16, y, " Toggle Godmode", "god\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, " Toggle Flymode", "fly\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, " Toggle Noclip", "noclip\n"); y+=8;
#ifndef CLIENTONLY
MC_AddSlider(menu, 16, y, " Gravity", &sv_gravity,0,800,25); y+=8;
MC_AddSlider(menu, 16, 170, y, "Gravity", &sv_gravity,0,800,25); y+=8;
#endif
MC_AddSlider(menu, 16, y, " Forward Speed", &cl_forwardspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, y, " Side Speed", &cl_sidespeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, y, " Back Speed", &cl_backspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Forward Speed", &cl_forwardspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Side Speed", &cl_sidespeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Back Speed", &cl_backspeed,0,1000,50); y+=8;
#ifndef CLIENTONLY
MC_AddSlider(menu, 16, y, " Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8;
MC_AddSlider(menu, 16, 170, y, "Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8;
#endif
MC_AddConsoleCommand(menu, 16, y, " Sheep Transformation", "impulse 14\n"); y+=8;
MC_AddConsoleCommand(menu, 16, y, " Change To Paladin (lvl3+)", "impulse 171\n"); y+=8;

View File

@ -5,32 +5,66 @@
int selectitem;
menu_t *menu_script;
cvar_t menualias = SCVAR("menualias", "");
void M_Script_Option (menu_t *menu, char *optionvalue)
{
menuoption_t *mo;
char buf[8192];
//update the option
Cbuf_AddText(va("set option %s\n", COM_QuotedString(optionvalue, buf, sizeof(buf))), RESTRICT_LOCAL);
//expand private arguments
for (mo = menu->options, *buf = 0; mo; mo = mo->common.next)
{
if (mo->common.type == mt_edit)
{
if (strlen(buf) + strlen(mo->edit.text) + 2 >= sizeof(buf))
break;
memmove(buf+strlen(mo->edit.text)+1, buf, strlen(buf)+1);
memcpy(buf, mo->edit.text, strlen(mo->edit.text));
buf[strlen(mo->edit.text)] = ' ';
}
}
Cmd_TokenizeString(buf, false, false);
Cmd_ExpandString(menu->data, buf, sizeof(buf), RESTRICT_SERVER, true, true);
//and execute it as-is
Cbuf_AddText(buf, RESTRICT_LOCAL);
Cbuf_AddText("\n", RESTRICT_LOCAL);
}
void M_Script_Remove (menu_t *menu)
{
menu_script = NULL;
Cbuf_AddText(va("set option cancel\n%s\n", menualias.string), RESTRICT_LOCAL);
Cvar_Set(&menualias, "");
if (menu == menu_script)
menu_script = NULL;
M_Script_Option(menu, "cancel");
}
qboolean M_Script_Key (int key, menu_t *menu)
{
if (menu->selecteditem && menu->selecteditem->common.type == mt_edit)
return false;
if (key >= '0' && key <= '9' && *menualias.string)
if (key >= '0' && key <= '9' && menu->data)
{
if (key == '0') //specal case so that "hello" < "0"... (plus matches common impulses)
Cbuf_AddText(va("set option %i\n%s\n", 10, menualias.string), RESTRICT_LOCAL);
M_Script_Option(menu, "10");
else
Cbuf_AddText(va("set option %i\n%s\n", key-'0', menualias.string), RESTRICT_LOCAL);
M_Script_Option(menu, va("%i", key-'0'));
return true;
}
return false;
}
void M_MenuS_Callback_f (void)
{
if (menu_script)
{
M_Script_Option(menu_script, Cmd_Argv(1));
}
}
void M_MenuS_Clear_f (void)
{
Cvar_Set(&menualias, "");
if (menu_script)
{
M_RemoveMenu(menu_script);
@ -76,10 +110,12 @@ void M_MenuS_Script_f (void) //create a menu.
menu_script->remove = M_Script_Remove;
menu_script->key = M_Script_Key;
if (Cmd_Argc() == 1 || !*alias)
Cvar_Set(&menualias, "_");
Key_Dest_Remove(kdm_console);
if (Cmd_Argc() == 1)
menu_script->data = Cmd_ParseMultiline(true);
else
Cvar_Set(&menualias, alias);
menu_script->data = Z_StrDup(alias);
}
void M_MenuS_Box_f (void)
@ -115,7 +151,7 @@ void M_MenuS_CheckBox_f (void)
cvar = Cvar_Get(cvarname, text, 0, "User variables");
if (!cvar)
return;
MC_AddCheckBox(menu_script, x, y, text, cvar, bitmask);
MC_AddCheckBox(menu_script, x, x+160, y, text, cvar, bitmask);
}
void M_MenuS_Slider_f (void)
@ -136,7 +172,7 @@ void M_MenuS_Slider_f (void)
cvar = Cvar_Get(cvarname, text, 0, "User variables");
if (!cvar)
return;
MC_AddSlider(menu_script, x, y, text, cvar, min, max, 0);
MC_AddSlider(menu_script, x, x+160, y, text, cvar, min, max, 0);
}
void M_MenuS_Picture_f (void)
@ -175,7 +211,22 @@ void M_MenuS_Edit_f (void)
return;
}
MC_AddEditCvar(menu_script, x, y, text, def);
MC_AddEditCvar(menu_script, x, x+160, y, text, def, false);
}
void M_MenuS_EditPriv_f (void)
{
int x = atoi(Cmd_Argv(1));
int y = atoi(Cmd_Argv(2));
char *text = Cmd_Argv(3);
char *def = Cmd_Argv(4);
if (!menu_script)
{
Con_Printf("%s with no active menu\n", Cmd_Argv(0));
return;
}
MC_AddEdit(menu_script, x, x+160, y, text, def);
}
void M_MenuS_Text_f (void)
@ -195,7 +246,7 @@ void M_MenuS_Text_f (void)
MC_AddBufferedText(menu_script, x, y, text, false, false);
else
{
option = (menuoption_t *)MC_AddConsoleCommand(menu_script, x, y, text, va("set option %s\n%s\n", command, menualias.string));
option = (menuoption_t *)MC_AddConsoleCommand(menu_script, x, y, text, va("menucallback %s\n", command));
if (selectitem-- == 0)
menu_script->selecteditem = option;
}
@ -218,7 +269,7 @@ void M_MenuS_TextBig_f (void)
MC_AddConsoleCommandQBigFont(menu_script, x, y, text, command);
else
{
option = (menuoption_t *)MC_AddConsoleCommandQBigFont(menu_script, x, y, text, va("set option %s\n%s\n", command, menualias.string));
option = (menuoption_t *)MC_AddConsoleCommandQBigFont(menu_script, x, y, text, va("menucallback %s\n", command));
if (selectitem-- == 0)
menu_script->selecteditem = option;
}
@ -240,7 +291,7 @@ void M_MenuS_Bind_f (void)
if (!*caption)
caption = command;
MC_AddBind(menu_script, x, y, command, caption);
MC_AddBind(menu_script, x, x+160, y, command, caption);
}
void M_MenuS_Comboi_f (void)
@ -278,7 +329,7 @@ void M_MenuS_Comboi_f (void)
}
opts[opt] = NULL;
MC_AddCvarCombo(menu_script, x, y, caption, var, (const char **)opts, (const char **)values);
MC_AddCvarCombo(menu_script, x, x+160, y, caption, var, (const char **)opts, (const char **)values);
}
char *Hunk_TempString(char *s)
@ -352,7 +403,7 @@ void M_MenuS_Combos_f (void)
}
opts[opt] = NULL;
MC_AddCvarCombo(menu_script, x, y, caption, var, (const char **)opts, (const char **)values);
MC_AddCvarCombo(menu_script, x, x+160, y, caption, var, (const char **)opts, (const char **)values);
}
/*
@ -370,10 +421,12 @@ menutext 0 24 "Cancel"
*/
void M_Script_Init(void)
{
Cmd_AddCommand("menuclear", M_MenuS_Clear_f);
Cmd_AddCommandD("menuclear", M_MenuS_Clear_f, "Pop the currently scripted menu.");
Cmd_AddCommandD("menucallback", M_MenuS_Callback_f, "Explicitly invoke the active script menu's callback function with the given option set.");
Cmd_AddCommand("conmenu", M_MenuS_Script_f);
Cmd_AddCommand("menubox", M_MenuS_Box_f);
Cmd_AddCommand("menuedit", M_MenuS_Edit_f);
Cmd_AddCommand("menueditpriv", M_MenuS_EditPriv_f);
Cmd_AddCommand("menutext", M_MenuS_Text_f);
Cmd_AddCommand("menutextbig", M_MenuS_TextBig_f);
Cmd_AddCommand("menupic", M_MenuS_Picture_f);
@ -382,6 +435,4 @@ void M_Script_Init(void)
Cmd_AddCommand("menubind", M_MenuS_Bind_f);
Cmd_AddCommand("menucomboi", M_MenuS_Comboi_f);
Cmd_AddCommand("menucombos", M_MenuS_Combos_f);
Cvar_Register(&menualias, "Scripting");
}

View File

@ -413,13 +413,13 @@ void M_Menu_Keys_f (void)
"3",
"4"
};
MC_AddCvarCombo(menu, 16, y, "Force client", &cl_forcesplitclient, (const char **)texts, (const char **)values);
MC_AddCvarCombo(menu, 16, 170, y, "Force client", &cl_forcesplitclient, (const char **)texts, (const char **)values);
y+=8;
}
while (bindnames->name)
{
MC_AddBind(menu, 16, y, bindnames->name, bindnames->command);
MC_AddBind(menu, 16, 170, y, bindnames->name, bindnames->command);
y += 8;
bindnames++;

View File

@ -143,8 +143,8 @@ typedef struct { //must be first of each structure type.
menutype_t type;
int posx;
int posy;
int width;
int height;
int width; //total width
int height; //total height
int extracollide; // dirty hack to stretch collide box left (the real fix is to have separate collide/render rects)
char *tooltip;
qboolean noselectionsound:1;
@ -164,6 +164,7 @@ typedef struct {
#define MAX_EDIT_LENGTH 256
typedef struct {
menucommon_t common;
int captionwidth;
const char *caption;
cvar_t *cvar;
char text[MAX_EDIT_LENGTH];
@ -180,6 +181,7 @@ typedef struct {
float largechange;
float vx;
cvar_t *var;
int textwidth;
const char *text;
} menuslider_t;
@ -187,6 +189,7 @@ typedef enum {CHK_CHECKED, CHK_TOGGLE} chk_set_t;
typedef struct menucheck_s {
menucommon_t common;
const char *text;
int textwidth;
cvar_t *var;
int bits;
float value;
@ -221,6 +224,7 @@ typedef struct {
typedef struct {
menucommon_t common;
int captionwidth;
const char *caption;
const char **options;
const char **values;
@ -231,6 +235,7 @@ typedef struct {
typedef struct {
menucommon_t common;
int captionwidth;
char *caption;
char *command;
} menubind_t;
@ -288,28 +293,27 @@ typedef struct menu_s {
menutext_t *MC_AddBufferedText(menu_t *menu, int x, int y, const char *text, qboolean rightalign, qboolean red);
menutext_t *MC_AddRedText(menu_t *menu, int x, int y, const char *text, qboolean rightalign);
menutext_t *MC_AddWhiteText(menu_t *menu, int x, int y, const char *text, qboolean rightalign);
menubind_t *MC_AddBind(menu_t *menu, int x, int y, const char *caption, char *command);
menubind_t *MC_AddBind(menu_t *menu, int cx, int bx, int y, const char *caption, char *command);
menubox_t *MC_AddBox(menu_t *menu, int x, int y, int width, int height);
menupicture_t *MC_AddPicture(menu_t *menu, int x, int y, int width, int height, char *picname);
menupicture_t *MC_AddSelectablePicture(menu_t *menu, int x, int y, char *picname);
menupicture_t *MC_AddCenterPicture(menu_t *menu, int y, int height, char *picname);
menupicture_t *MC_AddCursor(menu_t *menu, int x, int y);
menuslider_t *MC_AddSlider(menu_t *menu, int x, int y, const char *text, cvar_t *var, float min, float max, float delta);
menucheck_t *MC_AddCheckBox(menu_t *menu, int x, int y, const char *text, cvar_t *var, int cvarbitmask);
menucheck_t *MC_AddCheckBoxFunc(menu_t *menu, int x, int y, const char *text, qboolean (*func) (menucheck_t *option, menu_t *menu, chk_set_t set), int bits);
menuslider_t *MC_AddSlider(menu_t *menu, int tx, int sx, int y, const char *text, cvar_t *var, float min, float max, float delta);
menucheck_t *MC_AddCheckBox(menu_t *menu, int tx, int cx, int y, const char *text, cvar_t *var, int cvarbitmask);
menucheck_t *MC_AddCheckBoxFunc(menu_t *menu, int tx, int cx, int y, const char *text, qboolean (*func) (menucheck_t *option, menu_t *menu, chk_set_t set), int bits);
menubutton_t *MC_AddConsoleCommand(menu_t *menu, int x, int y, const char *text, const char *command);
menubutton_t *MC_AddConsoleCommandQBigFont(menu_t *menu, int x, int y, const char *text, const char *command);
mpic_t *QBigFontWorks(void);
menubutton_t *MC_AddConsoleCommandHexen2BigFont(menu_t *menu, int x, int y, const char *text, const char *command);
menubutton_t *VARGS MC_AddConsoleCommandf(menu_t *menu, int x, int y, const char *text, char *command, ...);
menubutton_t *MC_AddCommand(menu_t *menu, int x, int y, char *text, qboolean (*command) (union menuoption_s *,struct menu_s *,int));
menucombo_t *MC_AddCombo(menu_t *menu, int x, int y, const char *caption, const char **text, int initialvalue);
menucombo_t *MC_AddCombo(menu_t *menu, int tx, int cx, int y, const char *caption, const char **ops, int initialvalue);
menucombo_t *MC_AddCvarCombo(menu_t *menu, int tx, int cx, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values);
menubutton_t *MC_AddCommand(menu_t *menu, int x, int y, char *text, qboolean (*command) (union menuoption_s *,struct menu_s *,int));
menuedit_t *MC_AddEdit(menu_t *menu, int x, int y, char *text, char *def);
menuedit_t *MC_AddEditCvar(menu_t *menu, int x, int y, char *text, char *name);
menuedit_t *MC_AddEditCvarSlim(menu_t *menu, int x, int y, char *text, char *name);
menuedit_t *MC_AddEdit(menu_t *menu, int cx, int ex, int y, char *text, char *def);
menuedit_t *MC_AddEditCvar(menu_t *menu, int cx, int ex, int y, char *text, char *name, qboolean slim);
menucustom_t *MC_AddCustom(menu_t *menu, int x, int y, void *dptr, int dint);
menucombo_t *MC_AddCvarCombo(menu_t *menu, int x, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values);
typedef struct menubulk_s {
menutype_t type;

View File

@ -110,9 +110,16 @@ void R_DrawTextField(int x, int y, int w, int h, char *text, unsigned int defaul
#endif
extern void Mod_Init (void);
//mod_purge flags
enum mod_purge_e
{
MP_MAPCHANGED, //new map. old stuff no longer needed
MP_FLUSH, //user flush command. anything flushable goes.
MP_RESET //*everything* is destroyed. renderer is going down.
};
extern void Mod_ClearAll (void);
extern void Mod_Flush (qboolean force);
extern void Mod_Purge (enum mod_purge_e type);
extern struct model_s *Mod_ForName (char *name, qboolean crash);
extern struct model_s *Mod_FindName (char *name);
extern void *Mod_Extradata (struct model_s *mod); // handles caching
@ -138,7 +145,7 @@ char *Mod_GetBoneName(struct model_s *model, int bonenum);
void Draw_FunString(float x, float y, const void *str);
void Draw_AltFunString(float x, float y, const void *str);
void Draw_FunStringWidth(float x, float y, const void *str, int width);
void Draw_FunStringWidth(float x, float y, const void *str, int width, qboolean rightalign, qboolean highlight);
extern int r_regsequence;

View File

@ -593,7 +593,7 @@ int Master_KeyForName(char *keyname)
void Master_AddMaster (char *address, int type, char *description)
void Master_AddMaster (char *address, enum mastertype_e mastertype, enum masterprotocol_e protocol, char *description)
{
netadr_t adr;
master_t *mast;
@ -610,7 +610,7 @@ void Master_AddMaster (char *address, int type, char *description)
return;
}
if (type < MT_SINGLEQW) //broadcasts
if (mastertype == MT_BCAST) //broadcasts
{
if (adr.type == NA_IP)
adr.type = NA_BROADCAST_IP;
@ -622,13 +622,14 @@ void Master_AddMaster (char *address, int type, char *description)
for (mast = master; mast; mast = mast->next)
{
if (NET_CompareAdr(&mast->adr, &adr) && mast->type == type) //already exists.
if (NET_CompareAdr(&mast->adr, &adr) && mast->mastertype == mastertype && mast->protocoltype == protocol) //already exists.
return;
}
mast = Z_Malloc(sizeof(master_t)+strlen(description)+1+strlen(address)+1);
mast->adr = adr;
mast->address = mast->name + strlen(description)+1;
mast->type = type;
mast->mastertype = mastertype;
mast->protocoltype = protocol;
strcpy(mast->name, description);
strcpy(mast->address, address);
@ -663,25 +664,32 @@ void MasterInfo_Shutdown(void)
Z_Free(visibleservers);
}
void Master_AddMasterHTTP (char *address, int mastertype, char *description)
void Master_AddMasterHTTP (char *address, int mastertype, int protocoltype, char *description)
{
master_t *mast;
int servertype;
/* int servertype;
if (mastertype == MT_MASTERHTTPQW)
servertype = 0;
else
if (protocoltype == MP_DP)
servertype = SS_DARKPLACES;
else if (protocoltype == MP_Q2)
servertype = SS_QUAKE2;
else if (protocoltype == MP_Q3)
servertype = SS_QUAKE3;
else if (protocoltype == MP_NQ)
servertype = SS_NETQUAKE;
else
servertype = 0;
*/
for (mast = master; mast; mast = mast->next)
{
if (!strcmp(mast->address, address) && mast->type == mastertype) //already exists.
if (!strcmp(mast->address, address) && mast->mastertype == mastertype && mast->protocoltype == protocoltype) //already exists.
return;
}
mast = Z_Malloc(sizeof(master_t)+strlen(description)+1+strlen(address)+1);
mast->address = mast->name + strlen(description)+1;
mast->type = mastertype;
mast->servertype = servertype;
mast->mastertype = mastertype;
mast->protocoltype = protocoltype;
// mast->servertype = servertype;
strcpy(mast->name, description);
strcpy(mast->address, address);
@ -690,13 +698,16 @@ void Master_AddMasterHTTP (char *address, int mastertype, char *description)
}
//build a linked list of masters. Doesn't duplicate addresses.
qboolean Master_LoadMasterList (char *filename, int defaulttype, int depth)
qboolean Master_LoadMasterList (char *filename, qboolean withcomment, int defaulttype, int defaultprotocol, int depth)
{
vfsfile_t *f;
char line[1024];
char file[1024];
char *name, *next;
char name[1024];
char entry[1024];
char *next, *sep;
int servertype;
int protocoltype;
qboolean favourite;
if (depth <= 0)
return false;
@ -711,120 +722,126 @@ qboolean Master_LoadMasterList (char *filename, int defaulttype, int depth)
if (*line == '#') //comment
continue;
next = COM_Parse(line);
*name = 0;
favourite = false;
servertype = defaulttype;
protocoltype = defaultprotocol;
next = COM_ParseOut(line, entry, sizeof(entry));
if (!*com_token)
continue;
if (!strcmp(com_token, "file")) //special case. Add a port if you have a server named 'file'... (unlikly)
//special cases. Add a port if you have a server named 'file'... (unlikly)
if (!strcmp(entry, "file"))
{
next = COM_Parse(next);
if (withcomment)
next = COM_ParseOut(next, name, sizeof(name));
next = COM_ParseOut(next, entry, sizeof(entry));
if (!next)
continue;
Q_strncpyz(file, com_token, sizeof(file));
servertype = MT_BAD;
}
else if (!strcmp(entry, "master"))
{
if (withcomment)
next = COM_ParseOut(next, name, sizeof(name));
next = COM_ParseOut(next, entry, sizeof(entry));
if (!next)
continue;
servertype = MT_MASTERUDP;
}
else if (!strcmp(entry, "url"))
{
if (withcomment)
next = COM_ParseOut(next, name, sizeof(name));
next = COM_ParseOut(next, entry, sizeof(entry));
servertype = MT_MASTERHTTP;
}
else
*file = '\0';
*next = '\0';
next++;
name = COM_Parse(next);
servertype = -1;
next = COM_Parse(next);
if (!strcmp(com_token, "single:qw"))
servertype = MT_SINGLEQW;
else if (!strcmp(com_token, "single:q2"))
servertype = MT_SINGLEQ2;
else if (!strcmp(com_token, "single:q3"))
servertype = MT_SINGLEQ3;
else if (!strcmp(com_token, "single:dp"))
servertype = MT_SINGLEDP;
else if (!strcmp(com_token, "single:nq") || !strcmp(com_token, "single:q1"))
servertype = MT_SINGLENQ;
else if (!strcmp(com_token, "single"))
servertype = MT_SINGLEQW;
for(sep = com_token; sep; sep = next)
{
next = strchr(sep, ':');
if (next)
*next = 0;
else if (!strcmp(com_token, "master:dp"))
servertype = MT_MASTERDP;
else if (!strcmp(com_token, "master:qw"))
servertype = MT_MASTERQW;
else if (!strcmp(com_token, "master:q2"))
servertype = MT_MASTERQ2;
else if (!strcmp(com_token, "master:q3"))
servertype = MT_MASTERQ3;
else if (!strcmp(com_token, "master:httpjson"))
servertype = MT_MASTERHTTPJSON;
else if (!strcmp(com_token, "master:httpnq"))
servertype = MT_MASTERHTTPNQ;
else if (!strcmp(com_token, "master:httpqw"))
servertype = MT_MASTERHTTPQW;
else if (!strcmp(com_token, "master")) //any other sort of master, assume it's a qw master.
servertype = MT_MASTERQW;
if (!strcmp(sep, "single"))
servertype = MT_SINGLE;
else if (!strcmp(sep, "master"))
servertype = MT_MASTERUDP;
else if (!strcmp(sep, "masterhttp"))
servertype = MT_MASTERHTTP;
else if (!strcmp(sep, "masterhttpjson"))
servertype = MT_MASTERHTTPJSON;
else if (!strcmp(sep, "bcast"))
servertype = MT_BCAST;
else if (!strcmp(com_token, "bcast:qw"))
servertype = MT_BCASTQW;
else if (!strcmp(com_token, "bcast:q2"))
servertype = MT_BCASTQ2;
else if (!strcmp(com_token, "bcast:q3"))
servertype = MT_BCASTQ3;
else if (!strcmp(com_token, "bcast:nq"))
servertype = MT_BCASTNQ;
else if (!strcmp(com_token, "bcast:dp"))
servertype = MT_BCASTDP;
else if (!strcmp(com_token, "bcast"))
servertype = MT_BCASTQW;
else if (!strcmp(com_token, "qw"))
protocoltype = MP_QW;
else if (!strcmp(com_token, "q2"))
protocoltype = MP_Q2;
else if (!strcmp(com_token, "q3"))
protocoltype = MP_Q3;
else if (!strcmp(com_token, "nq"))
protocoltype = MP_NQ;
else if (!strcmp(com_token, "dp"))
protocoltype = MP_DP;
else if (!strcmp(com_token, "favorite:qw"))
servertype = -MT_SINGLEQW;
else if (!strcmp(com_token, "favorite:q2"))
servertype = -MT_SINGLEQ2;
else if (!strcmp(com_token, "favorite:q3"))
servertype = -MT_SINGLEQ3;
else if (!strcmp(com_token, "favorite:nq"))
servertype = -MT_SINGLENQ;
else if (!strcmp(com_token, "favorite"))
servertype = -MT_SINGLEQW;
//legacy compat
else if (!strcmp(com_token, "httpjson"))
{
servertype = MT_MASTERHTTPJSON;
protocoltype = MP_NQ;
}
else if (!strcmp(com_token, "httpnq"))
{
servertype = MT_MASTERHTTP;
protocoltype = MP_NQ;
}
else if (!strcmp(com_token, "httpqw"))
{
servertype = MT_MASTERHTTP;
protocoltype = MP_QW;
}
else if (!strcmp(com_token, "favourite") || !strcmp(com_token, "favorite"))
favourite = true;
}
if (!*name)
{
sep = name;
while(*next == ' ' || *next == '\t')
next++;
while (*next && sep < name+sizeof(name)-1)
*sep++ = *next++;
*sep = 0;
}
if (servertype == MT_BAD)
Master_LoadMasterList(entry, false, servertype, protocoltype, depth);
else
{
name = next; //go back one token.
servertype = defaulttype;
}
//favourites are added explicitly, with their name and stuff
if (favourite && servertype == MT_SINGLE)
{
if (NET_StringToAdr(entry, 0, &net_from))
CL_ReadServerInfo(va("\\hostname\\%s", name), -servertype, true);
else
Con_Printf("Failed to resolve address - \"%s\"\n", entry);
}
while(*name <= ' ' && *name != 0) //skip whitespace
name++;
next = name + strlen(name)-1;
while(*next <= ' ' && next > name)
{
*next = '\0';
next--;
}
if (*file)
Master_LoadMasterList(file, servertype, depth);
else if (servertype < 0)
{
if (NET_StringToAdr(line, 0, &net_from))
CL_ReadServerInfo(va("\\hostname\\%s", name), -servertype, true);
else
Con_Printf("Failed to resolve address - \"%s\"\n", line);
}
else
{
switch (servertype)
{
case MT_MASTERHTTPJSON:
case MT_MASTERHTTPNQ:
case MT_MASTERHTTPQW:
Master_AddMasterHTTP(line, servertype, name);
case MT_MASTERHTTP:
Master_AddMasterHTTP(entry, servertype, protocoltype, name);
break;
default:
Master_AddMaster(line, servertype, name);
Master_AddMaster(entry, servertype, protocoltype, name);
break;
}
}
}
VFS_CLOSE(f);
@ -832,7 +849,6 @@ qboolean Master_LoadMasterList (char *filename, int defaulttype, int depth)
return true;
}
void NET_SendPollPacket(int len, void *data, netadr_t to)
{
int ret;
@ -959,12 +975,12 @@ int Master_CheckPollSockets(void)
#ifdef Q2CLIENT
if (!strcmp(s, "print"))
{
CL_ReadServerInfo(MSG_ReadString(), MT_SINGLEQ2, false);
CL_ReadServerInfo(MSG_ReadString(), MP_Q2, false);
continue;
}
if (!strcmp(s, "info")) //parse a bit more...
{
CL_ReadServerInfo(MSG_ReadString(), MT_SINGLEQ2, false);
CL_ReadServerInfo(MSG_ReadString(), MP_Q2, false);
continue;
}
#ifdef IPPROTO_IPV6
@ -985,7 +1001,7 @@ int Master_CheckPollSockets(void)
#ifdef Q3CLIENT
if (!strcmp(s, "statusResponse"))
{
CL_ReadServerInfo(MSG_ReadString(), MT_SINGLEQ3, false);
CL_ReadServerInfo(MSG_ReadString(), MP_Q3, false);
continue;
}
#endif
@ -1006,7 +1022,7 @@ int Master_CheckPollSockets(void)
}
if (!strcmp(s, "infoResponse")) //parse a bit more...
{
CL_ReadServerInfo(MSG_ReadString(), MT_SINGLEDP, false);
CL_ReadServerInfo(MSG_ReadString(), MP_DP, false);
continue;
}
@ -1025,7 +1041,7 @@ int Master_CheckPollSockets(void)
if (c == A2C_PRINT) //qw server reply.
{
CL_ReadServerInfo(MSG_ReadString(), MT_SINGLEQW, false);
CL_ReadServerInfo(MSG_ReadString(), MP_QW, false);
continue;
}
@ -1070,7 +1086,7 @@ int Master_CheckPollSockets(void)
// Q_strcat(name, name);
}
CL_ReadServerInfo(va("\\hostname\\%s\\map\\%s\\maxclients\\%i\\clients\\%i", name, map, maxusers, users), MT_SINGLENQ, false);
CL_ReadServerInfo(va("\\hostname\\%s\\map\\%s\\maxclients\\%i\\clients\\%i", name, map, maxusers, users), MP_NQ, false);
}
#endif
continue;
@ -1136,14 +1152,18 @@ void SListOptionChanged(serverinfo_t *newserver)
}
#ifdef WEBCLIENT
void MasterInfo_ProcessHTTP(vfsfile_t *file, int type)
void MasterInfo_ProcessHTTP(struct dl_download *dl)
{
master_t *mast = dl->user_ctx;
vfsfile_t *file = dl->file;
int protocoltype = mast->protocoltype;
netadr_t adr;
char *s;
char *el;
serverinfo_t *info;
char adrbuf[MAX_ADR_SIZE];
char linebuffer[2048];
mast->dl = NULL;
if (!file)
return;
@ -1173,7 +1193,18 @@ void MasterInfo_ProcessHTTP(vfsfile_t *file, int type)
info = Z_Malloc(sizeof(serverinfo_t));
info->adr = adr;
info->sends = 1;
info->special = type;
if (protocoltype == MP_DP)
info->special = SS_DARKPLACES;
else if (protocoltype == MP_Q2)
info->special = SS_QUAKE2;
else if (protocoltype == MP_Q3)
info->special = SS_QUAKE3;
else if (protocoltype == MP_NQ)
info->special = SS_NETQUAKE;
else
info->special = 0;
info->refreshtime = 0;
info->ping = 0xffff;
@ -1307,25 +1338,10 @@ void MasterInfo_ProcessHTTPJSON(struct dl_download *dl)
Con_Printf("Unable to query master at \"%s\"\n", dl->url);
}
}
// wrapper functions for the different server types
void MasterInfo_ProcessHTTPNQ(struct dl_download *dl)
{
master_t *mast = dl->user_ctx;
mast->dl = NULL;
MasterInfo_ProcessHTTP(dl->file, SS_NETQUAKE);
}
void MasterInfo_ProcessHTTPQW(struct dl_download *dl)
{
master_t *mast = dl->user_ctx;
mast->dl = NULL;
MasterInfo_ProcessHTTP(dl->file, SS_GENERICQUAKEWORLD);
}
#endif
//don't try sending to servers we don't support
void MasterInfo_Request(master_t *mast, qboolean evenifwedonthavethefiles)
void MasterInfo_Request(master_t *mast)
{
//static int mastersequence; // warning: unused variable âmastersequenceâ
if (!mast)
@ -1334,68 +1350,9 @@ void MasterInfo_Request(master_t *mast, qboolean evenifwedonthavethefiles)
if (mast->sends)
mast->sends--;
switch(mast->type)
//these are generic requests
switch(mast->mastertype)
{
#ifdef Q3CLIENT
case MT_BCASTQ3:
case MT_SINGLEQ3:
NET_SendPollPacket (14, va("%c%c%c%cgetstatus\n", 255, 255, 255, 255), mast->adr);
break;
case MT_MASTERQ3:
{
char *str;
str = va("%c%c%c%cgetservers %u empty full\x0A\n", 255, 255, 255, 255, 68);
NET_SendPollPacket (strlen(str), str, mast->adr);
}
break;
#endif
#ifdef Q2CLIENT
case MT_BCASTQ2:
case MT_SINGLEQ2:
#endif
case MT_SINGLEQW:
case MT_BCASTQW:
NET_SendPollPacket (11, va("%c%c%c%cstatus\n", 255, 255, 255, 255), mast->adr);
break;
#ifdef NQPROT
case MT_BCASTNQ:
case MT_SINGLENQ:
SZ_Clear(&net_message);
net_message.packing = SZ_RAWBYTES;
net_message.currentbit = 0;
MSG_WriteLong(&net_message, 0);// save space for the header, filled in later
MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
MSG_WriteString(&net_message, NET_GAMENAME_NQ); //look for either sort of server
MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
NET_SendPollPacket(net_message.cursize, net_message.data, mast->adr);
SZ_Clear(&net_message);
break;
case MT_MASTERDP:
{
char *str;
str = va("%c%c%c%cgetservers %s %u empty full"/*\x0A\n"*/, 255, 255, 255, 255, com_protocolname.string, 3);
NET_SendPollPacket (strlen(str), str, mast->adr);
}
break;
case MT_SINGLEDP:
case MT_BCASTDP:
{
char *str;
str = va("%c%c%c%cgetinfo", 255, 255, 255, 255);
NET_SendPollPacket (strlen(str), str, mast->adr);
}
break;
#endif
case MT_MASTERQW:
NET_SendPollPacket (3, "c\n", mast->adr);
break;
#ifdef Q2CLIENT
case MT_MASTERQ2:
if (evenifwedonthavethefiles || COM_FDepthFile("pics/colormap.pcx", true)!=0x7fffffff) //only query this master if we expect to be able to load it's maps.
NET_SendPollPacket (6, "query", mast->adr);
break;
#endif
#ifdef WEBCLIENT
case MT_MASTERHTTPJSON:
if (!mast->dl)
@ -1405,30 +1362,94 @@ void MasterInfo_Request(master_t *mast, qboolean evenifwedonthavethefiles)
mast->dl->user_ctx = mast;
}
break;
case MT_MASTERHTTPNQ:
case MT_MASTERHTTP:
if (!mast->dl)
{
mast->dl = HTTP_CL_Get(mast->address, NULL, MasterInfo_ProcessHTTPNQ);
if (mast->dl)
mast->dl->user_ctx = mast;
}
break;
case MT_MASTERHTTPQW:
if (!mast->dl)
{
mast->dl = HTTP_CL_Get(mast->address, NULL, MasterInfo_ProcessHTTPQW);
mast->dl = HTTP_CL_Get(mast->address, NULL, MasterInfo_ProcessHTTP);
if (mast->dl)
mast->dl->user_ctx = mast;
}
break;
#endif
case MT_MASTERUDP:
switch(mast->protocoltype)
{
#ifdef Q3CLIENT
case MP_Q3:
{
char *str;
str = va("%c%c%c%cgetservers %u empty full\x0A\n", 255, 255, 255, 255, 68);
NET_SendPollPacket (strlen(str), str, mast->adr);
}
break;
#endif
#ifdef Q2CLIENT
case MP_Q2:
NET_SendPollPacket (6, "query", mast->adr);
break;
#endif
case MP_QW:
NET_SendPollPacket (3, "c\n", mast->adr);
break;
#ifdef NQPROT
case MP_NQ:
//there is no nq udp master protocol
break;
case MP_DP:
{
char *str;
str = va("%c%c%c%cgetservers %s %u empty full"/*\x0A\n"*/, 255, 255, 255, 255, com_protocolname.string, 3);
NET_SendPollPacket (strlen(str), str, mast->adr);
}
break;
#endif
}
break;
case MT_BCAST:
case MT_SINGLE: //FIXME: properly add the server and flag it for resending instead of directly pinging it
switch(mast->protocoltype)
{
#ifdef Q3CLIENT
case MP_Q3:
NET_SendPollPacket (14, va("%c%c%c%cgetstatus\n", 255, 255, 255, 255), mast->adr);
break;
#endif
#ifdef Q2CLIENT
case MP_Q2:
#endif
case MP_QW:
NET_SendPollPacket (11, va("%c%c%c%cstatus\n", 255, 255, 255, 255), mast->adr);
break;
#ifdef NQPROT
case MP_NQ:
SZ_Clear(&net_message);
net_message.packing = SZ_RAWBYTES;
net_message.currentbit = 0;
MSG_WriteLong(&net_message, 0);// save space for the header, filled in later
MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
MSG_WriteString(&net_message, NET_GAMENAME_NQ); //look for either sort of server
MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
NET_SendPollPacket(net_message.cursize, net_message.data, mast->adr);
SZ_Clear(&net_message);
break;
case MP_DP:
{
char *str;
str = va("%c%c%c%cgetinfo", 255, 255, 255, 255);
NET_SendPollPacket (strlen(str), str, mast->adr);
}
break;
#endif
}
break;
}
}
void MasterInfo_WriteServers(void)
{
char *typename;
char *typename, *protoname;
master_t *mast;
serverinfo_t *server;
vfsfile_t *mf, *qws;
@ -1443,58 +1464,51 @@ void MasterInfo_WriteServers(void)
for (mast = master; mast; mast=mast->next)
{
switch(mast->type)
switch(mast->mastertype)
{
case MT_MASTERQW:
typename = "master:qw";
case MT_MASTERUDP:
typename = "master";
break;
case MT_MASTERQ2:
typename = "master:q2";
case MT_MASTERHTTP:
typename = "masterhttp";
break;
case MT_MASTERQ3:
typename = "master:q3";
case MT_MASTERHTTPJSON:
typename = "masterjson";
break;
case MT_MASTERDP:
typename = "master:dp";
case MT_BCAST:
typename = "bcast";
break;
case MT_MASTERHTTPNQ:
typename = "master:httpnq";
break;
case MT_MASTERHTTPQW:
typename = "master:httpqw";
break;
case MT_BCASTQW:
typename = "bcast:qw";
break;
case MT_BCASTQ2:
typename = "bcast:q2";
break;
case MT_BCASTQ3:
typename = "bcast:q3";
break;
case MT_BCASTNQ:
typename = "bcast:nq";
break;
case MT_SINGLEQW:
typename = "single:qw";
break;
case MT_SINGLEQ2:
typename = "single:q2";
break;
case MT_SINGLEQ3:
typename = "single:q3";
break;
case MT_SINGLENQ:
typename = "single:nq";
break;
case MT_SINGLEDP:
typename = "single:dp";
case MT_SINGLE:
typename = "single";
break;
default:
typename = "writeerror";
typename = "??";
break;
}
switch(mast->protocoltype)
{
case MP_QW:
protoname = ":qw";
break;
case MP_Q2:
protoname = ":q2";
break;
case MP_Q3:
protoname = ":q3";
break;
case MP_NQ:
protoname = ":nq";
break;
case MP_DP:
protoname = ":dp";
break;
default:
case MP_UNSPECIFIED:
protoname = "";
break;
}
if (mast->address)
VFS_PUTS(mf, va("%s\t%s\t%s\n", mast->address , typename, mast->name));
VFS_PUTS(mf, va("%s\t%s\t%s\n", mast->address, typename, protoname, mast->name));
else
VFS_PUTS(mf, va("%s\t%s\t%s\n", NET_AdrToString(adr, sizeof(adr), &mast->adr), typename, mast->name));
}
@ -1516,7 +1530,7 @@ void MasterInfo_WriteServers(void)
VFS_PUTS(mf, va("%s\t%s\t%s\n", NET_AdrToString(adr, sizeof(adr), &server->adr), "favorite:q2", server->name));
else if (server->special & SS_NETQUAKE)
VFS_PUTS(mf, va("%s\t%s\t%s\n", NET_AdrToString(adr, sizeof(adr), &server->adr), "favorite:nq", server->name));
else if (qws) //servers.txt doesn't support the extra info.
else if (qws) //servers.txt doesn't support the extra info, so don't write it if its not needed
VFS_PUTS(qws, va("%s\t%s\n", NET_AdrToString(adr, sizeof(adr), &server->adr), server->name));
else //read only? damn them!
VFS_PUTS(mf, va("%s\t%s\t%s\n", NET_AdrToString(adr, sizeof(adr), &server->adr), "favorite:qw", server->name));
@ -1534,71 +1548,78 @@ void MasterInfo_WriteServers(void)
void MasterInfo_Refresh(void)
{
master_t *mast;
if (!Master_LoadMasterList("masters.txt", MT_MASTERQW, 5))
qboolean loadedone;
loadedone = false;
loadedone |= Master_LoadMasterList("masters.txt", false, MT_MASTERUDP, MP_QW, 5); //fte listing
loadedone |= Master_LoadMasterList("sources.txt", true, MT_MASTERUDP, MP_QW, 5); //merge with ezquake compat listing
if (!loadedone)
{
Master_LoadMasterList("servers.txt", MT_SINGLEQW, 1);
Master_LoadMasterList("servers.txt", false, MT_MASTERUDP, MP_QW, 1);
// if (q1servers) //qw master servers
{
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quakeworld", MT_MASTERHTTPQW, "gameaholic's QW master");
//Master_AddMaster("satan.idsoftware.com:27000", MT_MASTERQW, "id Limbo");
//Master_AddMaster("satan.idsoftware.com:27002", MT_MASTERQW, "id CTF");
//Master_AddMaster("satan.idsoftware.com:27003", MT_MASTERQW, "id TeamFortress");
//Master_AddMaster("satan.idsoftware.com:27004", MT_MASTERQW, "id Miscilaneous");
//Master_AddMaster("satan.idsoftware.com:27006", MT_MASTERQW, "id Deathmatch Only");
//Master_AddMaster("150.254.66.120:27000", MT_MASTERQW, "Poland's master server.");
//Master_AddMaster("62.112.145.129:27000", MT_MASTERQW, "Ocrana master server.");
//Master_AddMaster("master.edome.net", MT_MASTERQW, "edome master server.");
//Master_AddMaster("qwmaster.barrysworld.com", MT_MASTERQW, "barrysworld master server.");
//Master_AddMaster("213.221.174.165:27000", MT_MASTERQW, "unknown1 master server.");
//Master_AddMaster("195.74.0.8", MT_MASTERQW, "unknown2 master server.");
//Master_AddMaster("204.182.161.2", MT_MASTERQW, "unknown5 master server.");
//Master_AddMaster("kubus.rulez.pl:27000",MT_MASTERQW, "Kubus");
//Master_AddMaster("telefrag.me:27000",MT_MASTERQW, "Telefrag.ME");
//Master_AddMaster("master.teamdamage.com:27000", MT_MASTERQW, "TeamDamage");
Master_AddMaster("master.quakeservers.net:27000", MT_MASTERQW, "QuakeServers.net");
// Master_AddMaster("masterserver.exhale.de:27000", MT_MASTERQW, "team exhale");
Master_AddMaster("qwmaster.fodquake.net:27000", MT_MASTERQW, "Fodquake master server.");
Master_AddMaster("qwmaster.ocrana.de:27000", MT_MASTERQW, "Ocrana2 master server.");
Master_AddMaster("255.255.255.255:27500", MT_BCASTQW, "Nearby QuakeWorld UDP servers.");
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quakeworld", MT_MASTERHTTP, MP_QW, "gameaholic's QW master");
Master_AddMasterHTTP("http://www.quakeservers.net/lists/servers/global.txt",MT_MASTERHTTP, MP_QW, "QuakeServers.net (http)");
//Master_AddMaster("satan.idsoftware.com:27000", MT_MASTERUDP, MP_QW, "id Limbo");
//Master_AddMaster("satan.idsoftware.com:27002", MT_MASTERUDP, MP_QW, "id CTF");
//Master_AddMaster("satan.idsoftware.com:27003", MT_MASTERUDP, MP_QW, "id TeamFortress");
//Master_AddMaster("satan.idsoftware.com:27004", MT_MASTERUDP, MP_QW, "id Miscilaneous");
//Master_AddMaster("satan.idsoftware.com:27006", MT_MASTERUDP, MP_QW, "id Deathmatch Only");
//Master_AddMaster("150.254.66.120:27000", MT_MASTERUDP, MP_QW, "Poland's master server.");
//Master_AddMaster("62.112.145.129:27000", MT_MASTERUDP, MP_QW, "Ocrana master server.");
//Master_AddMaster("master.edome.net", MT_MASTERUDP, MP_QW, "edome master server.");
//Master_AddMaster("qwmaster.barrysworld.com", MT_MASTERUDP, MP_QW, "barrysworld master server.");
//Master_AddMaster("213.221.174.165:27000", MT_MASTERUDP, MP_QW, "unknown1 master server.");
//Master_AddMaster("195.74.0.8", MT_MASTERUDP, MP_QW, "unknown2 master server.");
//Master_AddMaster("204.182.161.2", MT_MASTERUDP, MP_QW, "unknown5 master server.");
//Master_AddMaster("kubus.rulez.pl:27000", MT_MASTERUDP, MP_QW, "Kubus");
//Master_AddMaster("telefrag.me:27000", MT_MASTERUDP, MP_QW, "Telefrag.ME");
//Master_AddMaster("master.teamdamage.com:27000", MT_MASTERUDP, MP_QW, "TeamDamage");
Master_AddMaster("master.quakeservers.net:27000", MT_MASTERUDP, MP_QW, "QuakeServers.net");
// Master_AddMaster("masterserver.exhale.de:27000", MT_MASTERUDP, MP_QW, "team exhale");
Master_AddMaster("qwmaster.fodquake.net:27000", MT_MASTERUDP, MP_QW, "Fodquake master server.");
Master_AddMaster("qwmaster.ocrana.de:27000", MT_MASTERUDP, MP_QW, "Ocrana2 master server.");
Master_AddMaster("255.255.255.255:27500", MT_BCAST, MP_QW, "Nearby QuakeWorld UDP servers.");
}
// if (q1servers) //nq master servers
{
//Master_AddMaster("12.166.196.192:27950", MT_MASTERDP, "DarkPlaces Master 3");
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTPNQ, "gameaholic's NQ master");
Master_AddMasterHTTP("http://servers.quakeone.com/index.php?format=json", MT_MASTERHTTPJSON, "quakeone's server listing");
Master_AddMaster("69.59.212.88:27950"/*"ghdigital.com:27950"*/, MT_MASTERDP, "DarkPlaces Master 1"); // LordHavoc
Master_AddMaster("64.22.107.125:27950"/*"dpmaster.deathmask.net:27950"*/, MT_MASTERDP, "DarkPlaces Master 2"); // Willis
Master_AddMaster("92.62.40.73:27950"/*"dpmaster.tchr.no:27950"*/, MT_MASTERDP, "DarkPlaces Master 3"); // tChr
//Master_AddMaster("12.166.196.192:27950", MT_MASTERUDP, MP_DP, "DarkPlaces Master 3");
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTP, MP_NQ, "gameaholic's NQ master");
Master_AddMasterHTTP("http://servers.quakeone.com/index.php?format=json", MT_MASTERHTTPJSON, MP_NQ, "quakeone's server listing");
Master_AddMaster("69.59.212.88:27950"/*"ghdigital.com:27950"*/, MT_MASTERUDP, MP_DP, "DarkPlaces Master 1"); // LordHavoc
Master_AddMaster("64.22.107.125:27950"/*"dpmaster.deathmask.net:27950"*/, MT_MASTERUDP, MP_DP, "DarkPlaces Master 2"); // Willis
Master_AddMaster("92.62.40.73:27950"/*"dpmaster.tchr.no:27950"*/, MT_MASTERUDP, MP_DP, "DarkPlaces Master 3"); // tChr
#ifdef IPPROTO_IPV6
//Master_AddMaster("[2001:41d0:2:1628::4450]:27950", MT_MASTERDP, "DarkPlaces Master 4"); // dpmaster.div0.qc.to (admin: divVerent)
//Master_AddMaster("[2001:41d0:2:1628::4450]:27950", MT_MASTERUDP, MP_DP, "DarkPlaces Master 4"); // dpmaster.div0.qc.to (admin: divVerent)
#endif
Master_AddMaster("255.255.255.255:26000", MT_BCASTNQ, "Nearby Quake1 servers");
Master_AddMaster("255.255.255.255:26000", MT_BCASTDP, "Nearby DarkPlaces servers");
Master_AddMaster("255.255.255.255:26000", MT_BCAST, MP_NQ, "Nearby Quake1 servers");
Master_AddMaster("255.255.255.255:26000", MT_BCAST, MP_DP, "Nearby DarkPlaces servers");
}
// if (q2servers) //q2
{
//Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake2", MT_MASTERHTTPQW, "gameaholic's Q2 master");
//Master_AddMaster("satan.idsoftware.com:27900", MT_MASTERQ2, "id q2 Master.");
//Master_AddMaster("master.planetgloom.com:27900",MT_MASTERQ2, "Planetgloom.com");
//Master_AddMaster("master.q2servers.com:27900", MT_MASTERQ2, "q2servers.com");
Master_AddMaster("netdome.biz:27900", MT_MASTERQ2, "Netdome.biz");
// Master_AddMaster("masterserver.exhale.de:27900",MT_MASTERQ2, "team exhale");
Master_AddMaster("255.255.255.255:27910", MT_BCASTQ2, "Nearby Quake2 UDP servers.");
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake2", MT_MASTERHTTP, MP_QW, "gameaholic's Q2 master");
//Master_AddMaster("satan.idsoftware.com:27900", MT_MASTERUDP, MP_Q2, "id q2 Master.");
//Master_AddMaster("master.planetgloom.com:27900", MT_MASTERUDP, MP_Q2, "Planetgloom.com");
//Master_AddMaster("master.q2servers.com:27900", MT_MASTERUDP, MP_Q2, "q2servers.com");
Master_AddMaster("netdome.biz:27900", MT_MASTERUDP, MP_Q2, "Netdome.biz");
// Master_AddMaster("masterserver.exhale.de:27900", MT_MASTERUDP, MP_Q2, "team exhale");
Master_AddMaster("255.255.255.255:27910", MT_BCAST, MP_Q2, "Nearby Quake2 UDP servers.");
#ifdef USEIPX
Master_AddMaster("00000000:ffffffffffff:27910", MT_BCASTQ2, "Nearby Quake2 IPX servers.");
Master_AddMaster("00000000:ffffffffffff:27910", MT_BCAST, MP_Q2, "Nearby Quake2 IPX servers.");
#endif
}
//q3
{
//Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake3", MT_MASTERHTTPQW, "gameaholic's Q3 master");
Master_AddMaster("master.quake3arena.com:27950", MT_MASTERQ3, "Quake3 master server.");
// Master_AddMaster("masterserver.exhale.de:27950", MT_MASTERQ3, "team exhale");
//Master_AddMaster("master3.quake3arena.com:27950", MT_MASTERQ3, "Quake3 master3 server.");
Master_AddMaster("255.255.255.255:27960", MT_BCASTQ3, "Nearby Quake3 UDP servers.");
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake3", MT_MASTERHTTP, MP_Q3, "gameaholic's Q3 master");
Master_AddMaster("master.quake3arena.com:27950", MT_MASTERUDP, MP_Q3, "Quake3 master server.");
// Master_AddMaster("masterserver.exhale.de:27950", MT_MASTERUDP, MP_Q3, "team exhale");
//Master_AddMaster("master3.quake3arena.com:27950", MT_MASTERUDP, MP_Q3, "Quake3 master3 server.");
Master_AddMaster("255.255.255.255:27960", MT_BCAST, MP_Q3, "Nearby Quake3 UDP servers.");
}
}
@ -1658,42 +1679,32 @@ void CL_QueryServers(void)
for (mast = master; mast; mast=mast->next)
{
switch (mast->type)
switch (mast->protocoltype)
{
case MT_BAD:
case MP_UNSPECIFIED:
continue;
case MT_MASTERHTTPNQ:
case MT_BCASTNQ:
case MT_SINGLENQ:
case MT_BCASTDP:
case MT_SINGLEDP:
case MT_MASTERDP:
case MP_DP: //dpmaster allows the client to specify the protocol to query. this means it always matches the current game type, so don't bother allowing the user to disable it.
break;
case MP_NQ:
if (sb_hidenetquake.value)
continue;
break;
case MT_MASTERHTTPQW:
case MT_BCASTQW:
case MT_SINGLEQW:
case MT_MASTERQW:
case MP_QW:
if (sb_hidequakeworld.value)
continue;
break;
case MT_BCASTQ2:
case MT_SINGLEQ2:
case MT_MASTERQ2:
case MP_Q2:
if (sb_hidequake2.value)
continue;
break;
case MT_BCASTQ3:
case MT_MASTERQ3:
case MT_SINGLEQ3:
case MP_Q3:
if (sb_hidequake3.value)
continue;
break;
}
if (mast->sends > 0)
MasterInfo_Request(mast, false);
MasterInfo_Request(mast);
}
@ -1849,7 +1860,7 @@ void MasterInfo_AddPlayer(netadr_t *serveradr, char *name, int ping, int frags,
}
//we got told about a server, parse it's info
int CL_ReadServerInfo(char *msg, int servertype, qboolean favorite)
int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favorite)
{
serverdetailedinfo_t details;
@ -1901,18 +1912,18 @@ int CL_ReadServerInfo(char *msg, int servertype, qboolean favorite)
else if (!strncmp(DISTRIBUTION, Info_ValueForKey(msg, "*version"), 3))
info->special |= SS_FTESERVER;
if (servertype == MT_SINGLEDP)
if (prototype == MP_DP)
{
if (atoi(Info_ValueForKey(msg, "protocol")) > 60)
info->special |= SS_QUAKE3;
else
info->special |= SS_DARKPLACES;
}
else if (servertype == MT_SINGLEQ2)
else if (prototype == MP_Q2)
info->special |= SS_QUAKE2;
else if (servertype == MT_SINGLEQ3)
else if (prototype == MP_Q3)
info->special |= SS_QUAKE3;
else if (servertype == MT_SINGLENQ)
else if (prototype == MP_NQ)
info->special |= SS_NETQUAKE;
if (favorite) //was specifically named, not retrieved from a master.
info->special |= SS_FAVORITE;
@ -1936,7 +1947,7 @@ int CL_ReadServerInfo(char *msg, int servertype, qboolean favorite)
if (!strcmp(Info_ValueForKey(msg, "*progs"), "666") && !strcmp(Info_ValueForKey(msg, "*version"), "2.91"))
info->special |= SS_PROXY; //qizmo
if (servertype == MT_SINGLEQ3 || servertype == MT_SINGLEQ2 || servertype == MT_SINGLEDP)
if (prototype == MP_Q3 || prototype == MP_Q2 || prototype == MP_DP)
{
Q_strncpyz(info->gamedir, Info_ValueForKey(msg, "gamename"), sizeof(info->gamedir));
Q_strncpyz(info->map, Info_ValueForKey(msg, "mapname"), sizeof(info->map));
@ -1966,7 +1977,7 @@ int CL_ReadServerInfo(char *msg, int servertype, qboolean favorite)
{
int clnum;
for (clnum=0; clnum < MAX_CLIENTS; clnum++)
for (clnum=0; clnum < cl.allocated_client_slots; clnum++)
{
nl = strchr(msg, '\n');
if (!nl)

View File

@ -560,12 +560,11 @@ void QCBUILTIN PF_shaderforname (pubprogfuncs_t *prinst, struct globalvars_s *pr
else
shad = R_RegisterSkin(str, NULL);
if (shad)
G_FLOAT(OFS_RETURN) = shad-r_shaders + 1;
G_FLOAT(OFS_RETURN) = shad->id+1;
else
G_FLOAT(OFS_RETURN) = 0;
}
void QCBUILTIN PF_cl_GetBindMap (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_VECTOR(OFS_RETURN)[0] = 1;

View File

@ -720,8 +720,8 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
out->skinnum = in->v->skin;
out->fatness = in->xv->fatness;
ival = in->xv->forceshader;
if (ival >= 1 && ival <= MAX_SHADERS)
out->forcedshader = r_shaders + (ival-1);
if (ival >= 1 && ival <= r_numshaders)
out->forcedshader = r_shaders[(ival-1)];
else
out->forcedshader = NULL;
@ -817,6 +817,7 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa
break;
case lfield_angles:
AngleVectors(G_VECTOR(OFS_PARM2), l->axis[0], l->axis[1], l->axis[2]);
VectorInverse(l->axis[1]);
break;
case lfield_fov:
l->fov = G_FLOAT(OFS_PARM2);
@ -852,6 +853,7 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa
}
static void QCBUILTIN PF_R_DynamicLight_Get(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
vec3_t v;
dlight_t *l;
unsigned int lno = G_FLOAT(OFS_PARM0);
enum lightfield_e field = G_FLOAT(OFS_PARM1);
@ -882,7 +884,10 @@ static void QCBUILTIN PF_R_DynamicLight_Get(pubprogfuncs_t *prinst, struct globa
G_FLOAT(OFS_RETURN) = l->style;
break;
case lfield_angles:
VectorAngles(l->axis[0], l->axis[2], G_VECTOR(OFS_RETURN));
VectorAngles(l->axis[0], l->axis[2], v);
G_FLOAT(OFS_RETURN+0) = v[0]?v[0]:0;
G_FLOAT(OFS_RETURN+1) = v[1]?v[1]:0;
G_FLOAT(OFS_RETURN+2) = v[2]?v[2]:0;
break;
case lfield_fov:
G_FLOAT(OFS_RETURN) = l->fov;
@ -3617,25 +3622,21 @@ static void QCBUILTIN PF_cs_registercommand (pubprogfuncs_t *prinst, struct glob
Cmd_AddCommand(str, CS_ConsoleCommand_f);
}
static qboolean csqc_usinglistener;
qboolean CSQC_SettingListener(void)
{ //stops the engine from setting the listener positions.
if (csqc_usinglistener)
{
csqc_usinglistener = false;
return true;
}
return false;
}
static void QCBUILTIN PF_cs_setlistener (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float *origin = G_VECTOR(OFS_PARM0);
float *forward = G_VECTOR(OFS_PARM1);
float *right = G_VECTOR(OFS_PARM2);
float *up = G_VECTOR(OFS_PARM3);
csqc_usinglistener = true;
S_UpdateListener(origin, forward, right, up);
S_Update();
int inwater = (prinst->callargc>4)?G_FLOAT(OFS_PARM4):false;
r_refdef.audio.defaulted = false;
// r_refdef.audio.entity = 0;
VectorCopy(origin, r_refdef.audio.origin);
VectorCopy(forward, r_refdef.audio.forward);
VectorCopy(right, r_refdef.audio.right);
VectorCopy(up, r_refdef.audio.up);
r_refdef.audio.inwater = inwater;
}
#define RSES_NOLERP 1
@ -3763,12 +3764,7 @@ void CSQC_PlayerStateToCSQC(int pnum, player_state_t *srcp, csqcedict_t *ent)
{
ent->xv->entnum = pnum+1;
if (cl.spectator && !Cam_DrawEntity(0, pnum+1))
{
ent->v->modelindex = 0;
}
else
ent->v->modelindex = srcp->modelindex;
ent->v->modelindex = srcp->modelindex;
ent->v->skin = srcp->skinnum;
CSQC_LerpStateToCSQC(&cl.lerpplayers[pnum], ent, true);
@ -4130,7 +4126,7 @@ static void QCBUILTIN PF_ReadServerEntityState(pubprogfuncs_t *prinst, struct gl
if (!pack)
return; //we're lagging. can't do anything, just don't update
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
srcp = &cl.frames[cl.validsequence&UPDATE_MASK].playerstate[i];
ent = deltaedplayerents[i];
@ -5072,8 +5068,6 @@ void CSQC_Shutdown(void)
in_sensitivityscale = 1;
csqc_world.num_edicts = 0;
csqc_usinglistener = false;
}
//when the qclib needs a file, it calls out to this function.
@ -5229,7 +5223,6 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
csprogs_promiscuous = anycsqc;
csprogs_checksum = checksum;
csqc_usinglistener = false;
csqc_mayread = false;
csqc_singlecheats = cls.demoplayback;

View File

@ -1512,7 +1512,7 @@ char *particle_set_high =
"randomvel 0\n"
"lightradius 350\n"
"lightrgb 0.4 0.2 0.05\n"
"lightrgb 1.4 1.2 1.05\n"
"lighttime 0.5\n"
"lightradiusfade 350\n"
"lightrgbfade 2 2 2 \n"

View File

@ -1447,7 +1447,7 @@ start:
if (node->visframe != r_visframecount)
return;
for (c = 0, clipplane = frustum; c < FRUSTUMPLANES; c++, clipplane++)
for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numplanes; c++, clipplane++)
{
if (!(clipflags & (1 << c)))
continue; // don't need to clip against it
@ -1556,7 +1556,7 @@ static void Surf_OrthoRecursiveWorldNode (mnode_t *node, unsigned int clipflags)
if (node->visframe != r_visframecount)
return;
for (c = 0, clipplane = frustum; c < 4; c++, clipplane++)
for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numplanes; c++, clipplane++)
{
if (!(clipflags & (1 << c)))
continue; // don't need to clip against it
@ -1813,7 +1813,7 @@ start:
if (node->visframe != r_visframecount)
return;
for (c = 0, clipplane = frustum; c < FRUSTUMPLANES; c++, clipplane++)
for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numplanes; c++, clipplane++)
{
if (!(clipflags & (1 << c)))
continue; // don't need to clip against it
@ -2065,6 +2065,21 @@ void Surf_SetupFrame(void)
VectorCopy(t2, player_maxs);
}
V_SetContentsColor (r_viewcontents);
if (r_refdef.audio.defaulted)
{
//first scene is the 'main' scene and audio defaults to that (unless overridden later in the frame)
r_refdef.audio.defaulted = false;
VectorCopy(r_origin, r_refdef.audio.origin);
VectorCopy(vpn, r_refdef.audio.forward);
VectorCopy(vright, r_refdef.audio.right);
VectorCopy(vup, r_refdef.audio.up);
if (r_viewcontents & FTECONTENTS_FLUID)
r_refdef.audio.inwater = true;
else
r_refdef.audio.inwater = false;
}
}
/*
@ -2247,7 +2262,7 @@ void Surf_DrawWorld (void)
if (currententity->model->fromgame == fg_quake3)
{
entvis = surfvis = R_MarkLeaves_Q3 ();
Surf_RecursiveQ3WorldNode (cl.worldmodel->nodes, (1<<FRUSTUMPLANES)-1);
Surf_RecursiveQ3WorldNode (cl.worldmodel->nodes, (1<<r_refdef.frustum_numplanes)-1);
//Surf_LeafWorldNode ();
}
else
@ -2453,7 +2468,7 @@ int Surf_NewLightmaps(int count, int width, int height, qboolean deluxe)
if (deluxe && ((i - numlightmaps)&1))
{
lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*8)*width*height);
lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*4)*width*height);
lightmap[i]->width = width;
lightmap[i]->height = height;
lightmap[i]->lightmaps = (qbyte*)(lightmap[i]+1);
@ -2462,7 +2477,7 @@ int Surf_NewLightmaps(int count, int width, int height, qboolean deluxe)
}
else
{
lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*8 + sizeof(stmap)*3)*width*height);
lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*4 + sizeof(stmap)*3)*width*height);
lightmap[i]->width = width;
lightmap[i]->height = height;
lightmap[i]->lightmaps = (qbyte*)(lightmap[i]+1);

View File

@ -138,6 +138,17 @@ typedef struct entity_s
#endif
} entity_t;
// plane_t structure
typedef struct mplane_s
{
vec3_t normal;
float dist;
qbyte type; // for texture axis selection and fast side tests
qbyte signbits; // signx + signy<<1 + signz<<1
qbyte pad[2];
} mplane_t;
#define MAXFRUSTUMPLANES 7 //4 side, 1 near, 1 far (fog), 1 water plane.
#define RDFD_FOV 1
typedef struct
{
@ -164,6 +175,9 @@ typedef struct
float m_projection[16];
float m_view[16];
mplane_t frustum[MAXFRUSTUMPLANES];
int frustum_numplanes;
vec4_t gfog_rgbd;
vrect_t pxrect; /*vrect, but in pixels rather than virtual coords*/
@ -177,6 +191,16 @@ typedef struct
int postproccube; /*postproc shader wants a cubemap, this is the mask of sides required*/
qbyte *forcedvis;
struct
{
qboolean defaulted;
vec3_t origin;
vec3_t forward;
vec3_t right;
vec3_t up;
int inwater;
} audio;
} refdef_t;
extern refdef_t r_refdef;
@ -217,7 +241,7 @@ int Surf_LightmapShift (struct model_s *model);
#define LMBLOCK_WIDTH 128
#define LMBLOCK_HEIGHT 128
typedef struct glRect_s {
unsigned char l,t,w,h;
unsigned short l,t,w,h;
} glRect_t;
typedef unsigned char stmap;
struct mesh_s;
@ -335,8 +359,8 @@ extern texid_t balltexture;
extern texid_t beamtexture;
extern texid_t ptritexture;
void Mod_Init (void);
void Mod_Shutdown (void);
void Mod_Init (qboolean initial);
void Mod_Shutdown (qboolean final);
int Mod_TagNumForName(struct model_s *model, char *name);
int Mod_SkinNumForName(struct model_s *model, char *name);
int Mod_FrameNumForName(struct model_s *model, char *name);
@ -357,6 +381,11 @@ void Mod_NowLoadExternal(void);
void GLR_LoadSkys (void);
void R_BloomRegister(void);
int Mod_RegisterModelFormatText(void *module, const char *formatname, char *magictext, qboolean (QDECL *load) (struct model_s *mod, void *buffer));
int Mod_RegisterModelFormatMagic(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (struct model_s *mod, void *buffer));
void Mod_UnRegisterModelFormat(int idx);
void Mod_UnRegisterAllModelFormats(void *module);
#ifdef RUNTIMELIGHTING
void LightFace (int surfnum);
void LightLoadEntities(char *entstring);

View File

@ -79,6 +79,7 @@ cvar_t r_drawflat = CVARF ("r_drawflat", "0",
CVAR_ARCHIVE | CVAR_SEMICHEAT | CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM);
cvar_t r_wireframe = CVARF ("r_wireframe", "0",
CVAR_CHEAT);
cvar_t r_refract_fbo = CVARD ("r_refract_fbo", "1", "Use an fbo for refraction. If 0, just renders as a portal and uses a copy of the current framebuffer.");
cvar_t gl_miptexLevel = CVAR ("gl_miptexLevel", "0");
cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE);
cvar_t r_drawviewmodelinvis = CVAR ("r_drawviewmodelinvis", "0");
@ -616,6 +617,7 @@ void Renderer_Init(void)
Cvar_Register (&r_waterstyle, GRAPHICALNICETIES);
Cvar_Register (&r_lavastyle, GRAPHICALNICETIES);
Cvar_Register (&r_wireframe, GRAPHICALNICETIES);
Cvar_Register (&r_refract_fbo, GRAPHICALNICETIES);
Cvar_Register (&r_stereo_separation, GRAPHICALNICETIES);
Cvar_Register (&r_stereo_method, GRAPHICALNICETIES);
@ -900,7 +902,7 @@ void R_ShutdownRenderer(void)
CL_AllowIndependantSendCmd(false); //FIXME: figure out exactly which parts are going to affect the model loading.
P_Shutdown();
Mod_Shutdown();
Mod_Shutdown(false);
IN_Shutdown();
@ -1095,7 +1097,7 @@ TRACE(("dbg: R_ApplyRenderer: isDedicated = true\n"));
#endif
}
TRACE(("dbg: R_ApplyRenderer: initing mods\n"));
Mod_Init();
Mod_Init(false);
// host_hunklevel = Hunk_LowMark();
@ -2020,10 +2022,6 @@ qbyte *R_MarkLeaves_Q1 (void)
return vis;
}
mplane_t frustum[FRUSTUMPLANES];
/*
=================
R_CullBox
@ -2033,10 +2031,15 @@ Returns true if the box is completely outside the frustom
*/
qboolean R_CullBox (vec3_t mins, vec3_t maxs)
{
//this isn't very precise.
//checking each plane individually can be problematic
//if you have a large object behind the view, it can cross multiple planes, and be infront of each one at some point, yet should still be outside the view.
//this is quite noticable with terrain where the potential height of a section is essentually infinite.
//note that this is not a concern for spheres, just boxes.
int i;
for (i=0 ; i<FRUSTUMPLANES ; i++)
if (BOX_ON_PLANE_SIDE (mins, maxs, &frustum[i]) == 2)
for (i = 0; i < r_refdef.frustum_numplanes; i++)
if (BOX_ON_PLANE_SIDE (mins, maxs, &r_refdef.frustum[i]) == 2)
return true;
return false;
}
@ -2047,9 +2050,9 @@ qboolean R_CullSphere (vec3_t org, float radius)
int i;
float d;
for (i=0 ; i<FRUSTUMPLANES ; i++)
for (i = 0; i < r_refdef.frustum_numplanes; i++)
{
d = DotProduct(frustum[i].normal, org)-frustum[i].dist;
d = DotProduct(r_refdef.frustum[i].normal, org)-r_refdef.frustum[i].dist;
if (d <= -radius)
return true;
}
@ -2157,38 +2160,55 @@ void R_SetFrustum (float projmat[16], float viewmat[16])
{
if (i & 1)
{
frustum[i].normal[0] = mvp[3] + mvp[0+i/2];
frustum[i].normal[1] = mvp[7] + mvp[4+i/2];
frustum[i].normal[2] = mvp[11] + mvp[8+i/2];
frustum[i].dist = mvp[15] + mvp[12+i/2];
r_refdef.frustum[i].normal[0] = mvp[3] + mvp[0+i/2];
r_refdef.frustum[i].normal[1] = mvp[7] + mvp[4+i/2];
r_refdef.frustum[i].normal[2] = mvp[11] + mvp[8+i/2];
r_refdef.frustum[i].dist = mvp[15] + mvp[12+i/2];
}
else
{
frustum[i].normal[0] = mvp[3] - mvp[0+i/2];
frustum[i].normal[1] = mvp[7] - mvp[4+i/2];
frustum[i].normal[2] = mvp[11] - mvp[8+i/2];
frustum[i].dist = mvp[15] - mvp[12+i/2];
r_refdef.frustum[i].normal[0] = mvp[3] - mvp[0+i/2];
r_refdef.frustum[i].normal[1] = mvp[7] - mvp[4+i/2];
r_refdef.frustum[i].normal[2] = mvp[11] - mvp[8+i/2];
r_refdef.frustum[i].dist = mvp[15] - mvp[12+i/2];
}
scale = 1/sqrt(DotProduct(frustum[i].normal, frustum[i].normal));
frustum[i].normal[0] *= scale;
frustum[i].normal[1] *= scale;
frustum[i].normal[2] *= scale;
frustum[i].dist *= -scale;
scale = 1/sqrt(DotProduct(r_refdef.frustum[i].normal, r_refdef.frustum[i].normal));
r_refdef.frustum[i].normal[0] *= scale;
r_refdef.frustum[i].normal[1] *= scale;
r_refdef.frustum[i].normal[2] *= scale;
r_refdef.frustum[i].dist *= -scale;
frustum[i].type = PLANE_ANYZ;
frustum[i].signbits = SignbitsForPlane (&frustum[i]);
r_refdef.frustum[i].type = PLANE_ANYZ;
r_refdef.frustum[i].signbits = SignbitsForPlane (&r_refdef.frustum[i]);
}
r_refdef.frustum_numplanes = 4;
if (r_refdef.recurse)
return;
#if FRUSTUMPLANES > 4
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] = mvp[3] - mvp[2];
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] = mvp[7] - mvp[6];
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] = mvp[11] - mvp[10];
r_refdef.frustum[r_refdef.frustum_numplanes].dist = mvp[15] - mvp[14];
scale = 1/sqrt(DotProduct(r_refdef.frustum[r_refdef.frustum_numplanes].normal, r_refdef.frustum[r_refdef.frustum_numplanes].normal));
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] *= scale;
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] *= scale;
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] *= scale;
r_refdef.frustum[r_refdef.frustum_numplanes].dist *= -scale;
r_refdef.frustum[r_refdef.frustum_numplanes].type = PLANE_ANYZ;
r_refdef.frustum[r_refdef.frustum_numplanes].signbits = SignbitsForPlane (&r_refdef.frustum[4]);
r_refdef.frustum_numplanes++;
//do far plane
//fog will not logically not actually reach 0, though precision issues will force it. we cut off at an exponant of -500
if (r_refdef.gfog_rgbd[3]
#ifdef TERRAIN
&& cl.worldmodel && cl.worldmodel->terrain
&& cl.worldmodel && cl.worldmodel->type == mod_heightmap
#else
&& 0
#endif
@ -2217,38 +2237,22 @@ void R_SetFrustum (float projmat[16], float viewmat[16])
culldist = culldist / (-r_refdef.gfog_rgbd[3]);
//anything drawn beyond this point is fully obscured by fog
frustum[4].normal[0] = mvp[3] - mvp[2];
frustum[4].normal[1] = mvp[7] - mvp[6];
frustum[4].normal[2] = mvp[11] - mvp[10];
frustum[4].dist = mvp[15] - mvp[14];
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] = mvp[3] - mvp[2];
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] = mvp[7] - mvp[6];
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] = mvp[11] - mvp[10];
r_refdef.frustum[r_refdef.frustum_numplanes].dist = mvp[15] - mvp[14];
scale = 1/sqrt(DotProduct(frustum[4].normal, frustum[4].normal));
frustum[4].normal[0] *= scale;
frustum[4].normal[1] *= scale;
frustum[4].normal[2] *= scale;
// frustum[4].dist *= scale;
frustum[4].dist = DotProduct(r_origin, frustum[4].normal)-culldist;
scale = 1/sqrt(DotProduct(r_refdef.frustum[r_refdef.frustum_numplanes].normal, r_refdef.frustum[r_refdef.frustum_numplanes].normal));
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] *= scale;
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] *= scale;
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] *= scale;
// r_refdef.frustum[r_refdef.frustum_numplanes].dist *= scale;
r_refdef.frustum[r_refdef.frustum_numplanes].dist = DotProduct(r_origin, r_refdef.frustum[r_refdef.frustum_numplanes].normal)-culldist;
frustum[4].type = PLANE_ANYZ;
frustum[4].signbits = SignbitsForPlane (&frustum[4]);
r_refdef.frustum[r_refdef.frustum_numplanes].type = PLANE_ANYZ;
r_refdef.frustum[r_refdef.frustum_numplanes].signbits = SignbitsForPlane (&r_refdef.frustum[r_refdef.frustum_numplanes]);
r_refdef.frustum_numplanes++;
}
else
{
frustum[4].normal[0] = mvp[3] - mvp[2];
frustum[4].normal[1] = mvp[7] - mvp[6];
frustum[4].normal[2] = mvp[11] - mvp[10];
frustum[4].dist = mvp[15] - mvp[14];
scale = 1/sqrt(DotProduct(frustum[4].normal, frustum[4].normal));
frustum[4].normal[0] *= scale;
frustum[4].normal[1] *= scale;
frustum[4].normal[2] *= scale;
frustum[4].dist *= -scale;
frustum[4].type = PLANE_ANYZ;
frustum[4].signbits = SignbitsForPlane (&frustum[4]);
}
#endif
}
#else
void R_SetFrustum (void)

View File

@ -176,23 +176,36 @@ void Draw_AltFunString(float x, float y, const void *str)
}
//Draws a marked up string no wider than $width virtual pixels.
void Draw_FunStringWidth(float x, float y, const void *str, int width)
void Draw_FunStringWidth(float x, float y, const void *str, int width, qboolean rightalign, qboolean highlight)
{
conchar_t buffer[2048];
conchar_t *w = buffer;
conchar_t *w;
int px, py;
int fw = 0;
width = (width*vid.rotpixelwidth)/vid.width;
COM_ParseFunString(CON_WHITEMASK, str, buffer, sizeof(buffer), false);
COM_ParseFunString(highlight?CON_ALTMASK:CON_WHITEMASK, str, buffer, sizeof(buffer), false);
Font_BeginString(font_conchar, x, y, &px, &py);
while(*w)
if (rightalign)
{
for (w = buffer; *w; w++)
{
fw += Font_CharWidth(*w);
}
px += width;
if (fw > width)
fw = width;
px -= fw;
}
for (w = buffer; *w; w++)
{
width -= Font_CharWidth(*w);
if (width < 0)
return;
px = Font_DrawChar(px, py, *w++);
px = Font_DrawChar(px, py, *w);
}
Font_EndString(font_conchar);
}
@ -1293,12 +1306,12 @@ void Sbar_SortTeams (playerview_t *pv)
memset(teams, 0, sizeof(teams));
// sort the teams
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
teams[i].plow = 999;
ownnum = Sbar_PlayerNum(pv);
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
playerteam[i] = -1;
s = &cl.players[i];
@ -2179,7 +2192,7 @@ static void Sbar_DrawTeamStatus(playerview_t *pv)
if (track == -1 || !cl.spectator)
track = pv->playernum;
for (p = 0; p < MAX_CLIENTS; p++)
for (p = 0; p < cl.allocated_client_slots; p++)
{
if (pv->playernum == p) //self is not shown
continue;
@ -2539,7 +2552,7 @@ void Sbar_IntermissionNumber (float x, float y, int num, int digits, int color,
}
#define COL_TEAM_LOWAVGHIGH COLUMN("low/avg/high", 12*8, {sprintf (num, "%3i/%3i/%3i", plow, pavg, phigh); Draw_FunString ( x, y, num); })
#define COL_TEAM_TEAM COLUMN("team", 4*8, {Draw_FunStringWidth ( x, y, tm->team, 4*8); \
#define COL_TEAM_TEAM COLUMN("team", 4*8, {Draw_FunStringWidth ( x, y, tm->team, 4*8, false, false); \
if (!strncmp(cl.players[pv->playernum].team, tm->team, 16))\
{\
Draw_FunString ( x - 1*8, y, "^Ue010");\
@ -2686,14 +2699,14 @@ ping time frags name
int p = s->ping; \
if (p < 0 || p > 999) p = 999; \
sprintf(num, "%4i", p); \
Draw_FunStringWidth(x, y, num, 4*8); \
Draw_FunStringWidth(x, y, num, 4*8, false, false); \
})
#define COLUMN_PL COLUMN(pl, 2*8, \
{ \
int p = s->pl; \
sprintf(num, "%2i", p); \
Draw_FunStringWidth(x, y, num, 2*8); \
Draw_FunStringWidth(x, y, num, 2*8, false, false); \
})
#define COLUMN_TIME COLUMN(time, 4*8, \
{ \
@ -2703,14 +2716,14 @@ ping time frags name
total = cl.servertime - s->entertime; \
minutes = (int)total/60; \
sprintf (num, "%4i", minutes); \
Draw_FunStringWidth(x, y, num, 4*8); \
Draw_FunStringWidth(x, y, num, 4*8, false, false); \
})
#define COLUMN_FRAGS COLUMN(frags, 5*8, \
{ \
int cx; int cy; \
if (s->spectator) \
{ \
Draw_FunStringWidth(x, y, "spectator", 5*8); \
Draw_FunStringWidth(x, y, "spectator", 5*8, false, false); \
} \
else \
{ \
@ -2745,15 +2758,15 @@ ping time frags name
{ \
if (!s->spectator) \
{ \
Draw_FunStringWidth(x, y, s->team, 4*8); \
Draw_FunStringWidth(x, y, s->team, 4*8, false, false); \
} \
})
#define COLUMN_NAME COLUMN(name, (cl.teamplay ? 12*8 : 16*8), {Draw_FunStringWidth(x, y, s->name, (cl.teamplay ? 12*8 : 16*8));})
#define COLUMN_KILLS COLUMN(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8);})
#define COLUMN_TKILLS COLUMN(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8);})
#define COLUMN_DEATHS COLUMN(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8);})
#define COLUMN_TOUCHES COLUMN(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8);})
#define COLUMN_CAPS COLUMN(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8);})
#define COLUMN_NAME COLUMN(name, (cl.teamplay ? 12*8 : 16*8), {Draw_FunStringWidth(x, y, s->name, (cl.teamplay ? 12*8 : 16*8), false, false);})
#define COLUMN_KILLS COLUMN(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8, false, false);})
#define COLUMN_TKILLS COLUMN(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8, false, false);})
#define COLUMN_DEATHS COLUMN(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8, false, false);})
#define COLUMN_TOUCHES COLUMN(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8, false, false);})
#define COLUMN_CAPS COLUMN(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8, false, false);})
@ -3185,11 +3198,11 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
// team and name
if (cl.teamplay)
{
Draw_FunStringWidth (x+48, y, s->team, 32);
Draw_FunStringWidth (x+48+40, y, name, MAX_DISPLAYEDNAME*8);
Draw_FunStringWidth (x+48, y, s->team, 32, false, false);
Draw_FunStringWidth (x+48+40, y, name, MAX_DISPLAYEDNAME*8, false, false);
}
else
Draw_FunStringWidth (x+48, y, name, MAX_DISPLAYEDNAME*8);
Draw_FunStringWidth (x+48, y, name, MAX_DISPLAYEDNAME*8, false, false);
y += 8;
}
@ -3211,7 +3224,7 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
tm = teams + k;
// draw pings
Draw_FunStringWidth (x, y, tm->team, 32);
Draw_FunStringWidth (x, y, tm->team, 32, false, false);
// draw total
sprintf (num, "%5i", tm->frags);

View File

@ -621,10 +621,10 @@ void Skin_NextDownload (void)
void Skin_FlushPlayers(void)
{ //wipe the skin info
int i;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
cl.players[i].skin = NULL;
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
}

View File

@ -987,6 +987,13 @@ void VARGS Sys_Error (const char *error, ...)
SetHookState(false);
#endif
TL_Shutdown();
#ifdef USE_MSVCRT_DEBUG
if (_CrtDumpMemoryLeaks())
OutputDebugStringA("Leaks detected\n");
#endif
exit (1);
}

View File

@ -167,13 +167,13 @@ void Validation_CheckIfResponse(char *text)
namelen = comp - text-1;
for (f_query_client = 0; f_query_client < MAX_CLIENTS; f_query_client++)
for (f_query_client = 0; f_query_client < cl.allocated_client_slots; f_query_client++)
{
if (strlen(cl.players[f_query_client].name) == namelen)
if (!strncmp(cl.players[f_query_client].name, text, namelen))
break;
}
if (f_query_client == MAX_CLIENTS)
if (f_query_client == cl.allocated_client_slots)
return; //looks like a validation, but it's not from a known client.
}

View File

@ -1416,7 +1416,7 @@ void R_DrawNameTags(void)
}
#endif
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (!nametagseen[i])
continue;

View File

@ -881,7 +881,7 @@ static void CountNearbyPlayers(qboolean dead)
state = cl.inframes[cl.oldparsecount & UPDATE_MASK].playerstate;
info = cl.players;
for (i = 0; i < MAX_CLIENTS; i++, info++, state++) {
for (i = 0; i < cl.allocated_client_slots; i++, info++, state++) {
if (i != cl.playerview[SP].playernum && state->messagenum == cl.oldparsecount && !info->spectator && !ISDEAD(state->frame)) {
if (cl.teamplay && !strcmp(info->team, TP_PlayerTeam()))
vars.numfriendlies++;
@ -1760,7 +1760,7 @@ int TP_CountPlayers (void)
int i, count;
count = 0;
for (i = 0; i < MAX_CLIENTS ; i++) {
for (i = 0; i < cl.allocated_client_slots ; i++) {
if (cl.players[i].name[0] && !cl.players[i].spectator)
count++;
}
@ -1779,7 +1779,7 @@ char *TP_EnemyTeam (void)
static char enemyteam[MAX_INFO_KEY];
char *myteam = TP_PlayerTeam();
for (i = 0; i < MAX_CLIENTS ; i++) {
for (i = 0; i < cl.allocated_client_slots ; i++) {
if (cl.players[i].name[0] && !cl.players[i].spectator)
{
strcpy (enemyteam, cl.players[i].team);
@ -1804,7 +1804,7 @@ char *TP_EnemyName (void)
myname = TP_PlayerName ();
for (i = 0; i < MAX_CLIENTS ; i++) {
for (i = 0; i < cl.allocated_client_slots ; i++) {
if (cl.players[i].name[0] && !cl.players[i].spectator)
{
strcpy (enemyname, cl.players[i].name);
@ -1945,7 +1945,7 @@ static void TP_Colourise_f (void)
}
Skin_FlushPlayers();
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
cl.players[i].colourised = TP_FindColours(cl.players[i].name);
CL_NewTranslation(i);
@ -1989,7 +1989,7 @@ static void TP_TeamColor_f (void)
cl_teambottomcolor = bottom;
if (qrenderer != QR_NONE) //make sure we have the renderer initialised...
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
}
}
@ -2030,7 +2030,7 @@ static void TP_EnemyColor_f (void)
cl_enemybottomcolor = bottom;
if (qrenderer != QR_NONE) //make sure we have the renderer initialised...
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
}
}
@ -2098,7 +2098,7 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr)
*offset = 0;
*plr = NULL;
for (i=0, player=cl.players ; i < MAX_CLIENTS ; i++, player++)
for (i=0, player=cl.players ; i < cl.allocated_client_slots ; i++, player++)
{
name = player->name;
if (!(*name))
@ -2562,7 +2562,7 @@ static int CountTeammates (void)
count = 0;
myteam = cl.players[cl.playerview[SP].playernum].team;
for (i=0, player=cl.players; i < MAX_CLIENTS ; i++, player++) {
for (i=0, player=cl.players; i < cl.allocated_client_slots ; i++, player++) {
if (player->name[0] && !player->spectator && (i != cl.playerview[SP].playernum)
&& !strcmp(player->team, myteam))
count++;
@ -2588,7 +2588,7 @@ static qboolean CheckTrigger (void)
count = 0;
myteam = cl.players[cl.playerview[SP].playernum].team;
for (i = 0, player= cl.players; i < MAX_CLIENTS; i++, player++) {
for (i = 0, player= cl.players; i < cl.allocated_client_slots; i++, player++) {
if (player->name[0] && !player->spectator && i != cl.playerview[SP].playernum && !strcmp(player->team, myteam))
count++;
}
@ -2845,7 +2845,7 @@ static char *Utils_TF_ColorToTeam_Failsafe(int color)
memset(teams, 0, sizeof(teams));
memset(teamcounts, 0, sizeof(teamcounts));
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
if (!cl.players[i].name[0] || cl.players[i].spectator)
continue;
@ -2974,7 +2974,7 @@ static void TP_FindPoint (void)
state = cl.inframes[cl.parsecount & UPDATE_MASK].playerstate;
info = cl.players;
for (j = 0; j < MAX_CLIENTS; j++, info++, state++)
for (j = 0; j < cl.allocated_client_slots; j++, info++, state++)
{
if (state->messagenum != cl.parsecount || j == cl.playerview[SP].playernum || info->spectator)
continue;

View File

@ -236,7 +236,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define CL_MASTER //query master servers and stuff for a dynamic server listing.
#define R_XFLIP //allow view to be flipped horizontally
#define TEXTEDITOR
#define DDS //a sort of image file format.
#define IMAGEFMT_DDS //a sort of image file format.
#define IMAGEFMT_BLP //a sort of image file format.
#ifndef RTLIGHTS
#define RTLIGHTS //realtime lighting
#endif
@ -403,7 +404,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef SERVERONLY
// undefine things not supported yet for D3D
#if defined(D3DQUAKE) && !defined(GLQUAKE)
#undef DDS // this is dumb
#undef IMAGEFMT_DDS // this is dumb
#undef IMAGEFMT_BLP // this is dumb
#endif
#endif

View File

@ -544,6 +544,8 @@ void Cmd_Exec_f (void)
s+=3;
}
// don't execute anything if it was from server (either the stuffcmd/localcmd, or the file)
if (!strcmp(name, "default.cfg") && !(Cmd_FromGamecode() || com_file_untrusted))
Cbuf_InsertText ("\ncvar_lockdefaults 1\n", ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), true);
Cbuf_InsertText (s, ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), true);
FS_FreeFile(f);
}
@ -585,6 +587,53 @@ void Cmd_ShowAlias_f (void)
Con_Printf("Alias doesn't exist\n");
}
//returns a zoned string.
char *Cmd_ParseMultiline(qboolean checkheader)
{
char *result;
char *end;
int in = checkheader?0:1;
char *s;
result = NULL;
for(;;)
{
s = Cbuf_GetNext(Cmd_ExecLevel, false);
if (!*s)
{
if (in)
Con_Printf(CON_WARNING "WARNING: Multiline alias was not terminated\n");
break;
}
while (*s <= ' ' && *s)
s++;
for (end = s + strlen(s)-1; end >= s && *end <= ' '; end--)
*end = '\0';
if (!strcmp(s, "{"))
{
in++;
if (in == 1)
continue; //don't embed the first one in the string, because that would be weird.
}
else if (!strcmp(s, "}"))
{
in--;
if (!in)
break; //phew
}
if (result)
{
char *newv = (char*)Z_Malloc(strlen(result) + strlen(s) + 2);
sprintf(newv, "%s;%s", result, s);
Z_Free(result);
result = newv;
}
else
result = Z_StrDup(s);
if (!in)
break;
}
return result;
}
/*
===============
Cmd_Alias_f
@ -723,41 +772,7 @@ void Cmd_Alias_f (void)
if (multiline)
{ //fun! MULTILINE ALIASES!!!!
char *newv;
char *end;
int in = 1;
a->value = NULL;
for(;;)
{
s = Cbuf_GetNext(Cmd_ExecLevel, false);
if (!*s)
{
Con_Printf(CON_WARNING "WARNING: Multiline alias was not terminated\n");
break;
}
while (*s <= ' ' && *s)
s++;
for (end = s + strlen(s)-1; end >= s && *end <= ' '; end--)
*end = '\0';
if (!strcmp(s, "{"))
in++;
else if (!strcmp(s, "}"))
{
in--;
if (!in)
break; //phew
}
if (a->value)
{
newv = (char*)Z_Malloc(strlen(a->value) + strlen(s) + 2);
sprintf(newv, "%s;%s", a->value, s);
Z_Free(a->value);
a->value = newv;
}
else
a->value = Z_StrDup(s);
}
a->value = Cmd_ParseMultiline(false);
return;
}
@ -977,6 +992,8 @@ void Alias_WipeStuffedAliases(void)
void Cvar_List_f (void);
void Cvar_Reset_f (void);
void Cvar_LockDefaults_f(void);
void Cvar_PurgeDefaults_f(void);
/*
=============================================================================
@ -2729,6 +2746,11 @@ void Cmd_set_f(void)
Con_Printf ("Server tried setting %s cvar\n", var->name);
return;
}
if (var->flags & CVAR_NOSET)
{
Con_Printf ("variable %s is readonly\n", var->name);
return;
}
if (Cmd_FromGamecode())
{
@ -3074,6 +3096,8 @@ void Cmd_Init (void)
Cmd_AddCommand ("macrolist", Cmd_MacroList_f);
Cmd_AddCommand ("cvarlist", Cvar_List_f);
Cmd_AddCommand ("cvarreset", Cvar_Reset_f);
Cmd_AddCommand ("cvar_lockdefaults", Cvar_LockDefaults_f);
Cmd_AddCommand ("cvar_purgedefaults", Cvar_PurgeDefaults_f);
Cmd_AddCommand ("fs_flush", COM_RefreshFSCache_f);
Cmd_AddMacro("time", Macro_Time, true);
@ -3090,7 +3114,7 @@ void Cmd_Init (void)
Cvar_Register (&cl_warncmd, "Warnings");
#ifndef SERVERONLY
rcon_level.ival = atof(rcon_level.defaultstr); //client is restricted to not be allowed to change restrictions.
rcon_level.ival = atof(rcon_level.enginevalue); //client is restricted to not be allowed to change restrictions.
#else
Cvar_Register(&rcon_level, "Access controls"); //server gains versatility.
#endif

View File

@ -101,6 +101,11 @@ char *VARGS Cmd_Argv (int arg);
char *VARGS Cmd_Args (void);
extern int Cmd_ExecLevel;
//if checkheader is false, an opening { is expected to already have been parsed.
//otherwise returns the contents of the block much like c.
//returns a zoned string.
char *Cmd_ParseMultiline(qboolean checkheader);
extern cvar_t cmd_gamecodelevel, cmd_allowaccess;
// The functions that execute commands get their parameters with these
// functions. Cmd_Argv () will return an empty string, not a NULL

View File

@ -1459,8 +1459,15 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
if (!inf->groups)
{
Con_DPrintf("Model with no frames (%s)\n", e->model->name);
return false;
#ifdef SKELETALMODELS
if (inf->ofs_skel_xyz && !inf->ofs_skel_weight)
{}
else
#endif
{
Con_DPrintf("Model with no frames (%s)\n", e->model->name);
return false;
}
}
if (meshcache.numcolours < inf->numverts)
@ -1743,16 +1750,25 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
//The whole reason why model loading is supported in the server.
qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentsmask, trace_t *trace)
static float PlaneNearest(vec3_t normal, vec3_t mins, vec3_t maxs)
{
galiasinfo_t *mod = Mod_Extradata(model);
galiasgroup_t *group;
galiaspose_t *pose;
float result;
return 128;
#if 1
result = fabs(normal[0] * maxs[0]);
result += fabs(normal[1] * maxs[1]);
result += fabs(normal[2] * maxs[2]);
#else
result = normal[0] * ((normal[0] < 0)?mins[0]:maxs[0]);
result += normal[1] * ((normal[1] < 0)?mins[1]:maxs[1]);
result += normal[2] * ((normal[2] < 0)?mins[2]:maxs[2]);
#endif
return result;
}
static qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace)
{
qboolean impacted = false;
int i;
float *p1, *p2, *p3;
@ -1762,88 +1778,166 @@ qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3],
float planedist;
float diststart, distend;
float expand;
float frac;
// float temp;
vec3_t impactpoint;
for (i = 0; i < numindexes; i+=3)
{
p1 = posedata[indexes[i+0]];
p2 = posedata[indexes[i+1]];
p3 = posedata[indexes[i+2]];
VectorSubtract(p1, p2, edge1);
VectorSubtract(p3, p2, edge2);
CrossProduct(edge1, edge2, normal);
expand = PlaneNearest(normal, mins, maxs);
planedist = DotProduct(p1, normal);
diststart = DotProduct(start, normal);
if (diststart <= planedist)
continue; //start on back side.
distend = DotProduct(end, normal);
if (distend >= planedist)
continue; //end on front side (as must start - doesn't cross).
frac = (diststart - planedist - 1) / (diststart-distend);
if (frac < 0)
frac = 0;
if (frac >= trace->fraction) //already found one closer.
continue;
impactpoint[0] = start[0] + frac*(end[0] - start[0]);
impactpoint[1] = start[1] + frac*(end[1] - start[1]);
impactpoint[2] = start[2] + frac*(end[2] - start[2]);
// temp = DotProduct(impactpoint, normal)-planedist;
CrossProduct(edge1, normal, edgenormal);
// temp = DotProduct(impactpoint, edgenormal)-DotProduct(p2, edgenormal);
if (DotProduct(impactpoint, edgenormal) > DotProduct(p2, edgenormal))
continue;
CrossProduct(normal, edge2, edgenormal);
if (DotProduct(impactpoint, edgenormal) > DotProduct(p3, edgenormal))
continue;
VectorSubtract(p1, p3, edge3);
CrossProduct(normal, edge3, edgenormal);
if (DotProduct(impactpoint, edgenormal) > DotProduct(p1, edgenormal))
continue;
trace->fraction = frac;
VectorCopy(impactpoint, trace->endpos);
VectorCopy(normal, trace->plane.normal);
impacted = true;
}
return impacted;
}
//The whole reason why model loading is supported in the server.
qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentsmask, trace_t *trace)
{
galiasinfo_t *mod = Mod_Extradata(model);
galiasgroup_t *group;
galiaspose_t *pose;
float frac;
// float temp;
vecV_t *posedata;
index_t *indexes;
int surfnum = 0;
int cursurfnum = -1;
vec3_t start_l, end_l;
if (axis)
{
start_l[0] = DotProduct(start, axis[0]);
start_l[1] = DotProduct(start, axis[1]);
start_l[2] = DotProduct(start, axis[2]);
end_l[0] = DotProduct(end, axis[0]);
end_l[1] = DotProduct(end, axis[1]);
end_l[2] = DotProduct(end, axis[2]);
}
else
{
VectorCopy(start, start_l);
VectorCopy(end, end_l);
}
while(mod)
{
indexes = mod->ofs_indexes;
group = mod->groupofs;
pose = group[0].poseofs;
posedata = pose->ofsverts;
#ifdef SKELETALMODELS
if (mod->numbones && mod->shares_verts != cursurfnum)
if (!mod->groups)
{
float bonepose[MAX_BONES][12];
posedata = alloca(mod->numverts*sizeof(vecV_t));
frac = 1;
if (group->isheirachical)
{
if (mod->shares_bones != cursurfnum)
R_LerpBones(&frac, (float**)posedata, 1, mod->ofsbones, mod->numbones, bonepose);
Alias_TransformVerticies_SW((float*)bonepose, mod->ofsswtransforms, mod->numswtransforms, posedata, NULL);
}
else
Alias_TransformVerticies_SW((float*)posedata, mod->ofsswtransforms, mod->numswtransforms, posedata, NULL);
cursurfnum = mod->shares_verts;
//certain models have no possibility of animation.
posedata = mod->ofs_skel_xyz;
}
else
#endif
for (i = 0; i < mod->numindexes; i+=3)
{
p1 = posedata[indexes[i+0]];
p2 = posedata[indexes[i+1]];
p3 = posedata[indexes[i+2]];
group = mod->groupofs;
pose = group[0].poseofs;
posedata = pose->ofsverts;
#ifdef SKELETALMODELS
if (mod->numbones && mod->shares_verts != cursurfnum)
{
float bonepose[MAX_BONES][12];
posedata = alloca(mod->numverts*sizeof(vecV_t));
frac = 1;
if (group->isheirachical)
{
if (mod->shares_bones != cursurfnum)
R_LerpBones(&frac, (float**)posedata, 1, mod->ofsbones, mod->numbones, bonepose);
Alias_TransformVerticies_SW((float*)bonepose, mod->ofsswtransforms, mod->numswtransforms, posedata, NULL);
}
else
Alias_TransformVerticies_SW((float*)posedata, mod->ofsswtransforms, mod->numswtransforms, posedata, NULL);
VectorSubtract(p1, p2, edge1);
VectorSubtract(p3, p2, edge2);
CrossProduct(edge1, edge2, normal);
cursurfnum = mod->shares_verts;
}
#endif
}
planedist = DotProduct(p1, normal);
diststart = DotProduct(start, normal);
if (diststart <= planedist)
continue; //start on back side.
distend = DotProduct(end, normal);
if (distend >= planedist)
continue; //end on front side (as must start - doesn't cross).
if (Mod_Trace_Trisoup(posedata, indexes, mod->numindexes, start_l, end_l, mins, maxs, trace) && axis)
{
if (axis)
{
vec3_t iaxis[3];
vec3_t norm;
Matrix3x3_RM_Invert_Simple((void *)axis, iaxis);
VectorCopy(trace->plane.normal, norm);
trace->plane.normal[0] = DotProduct(norm, iaxis[0]);
trace->plane.normal[1] = DotProduct(norm, iaxis[1]);
trace->plane.normal[2] = DotProduct(norm, iaxis[2]);
}
frac = (diststart - planedist) / (diststart-distend);
// frac = traceinfo.truefraction;
/*
diststart = DotProduct(traceinfo.start, trace->plane.normal);
distend = DotProduct(traceinfo.end, trace->plane.normal);
if (diststart == distend)
frac = 0;
else
{
frac = (diststart - trace->plane.dist) / (diststart-distend);
if (frac < 0)
frac = 0;
else if (frac > 1)
frac = 1;
}*/
if (frac >= trace->fraction) //already found one closer.
continue;
impactpoint[0] = start[0] + frac*(end[0] - start[0]);
impactpoint[1] = start[1] + frac*(end[1] - start[1]);
impactpoint[2] = start[2] + frac*(end[2] - start[2]);
// temp = DotProduct(impactpoint, normal)-planedist;
CrossProduct(edge1, normal, edgenormal);
// temp = DotProduct(impactpoint, edgenormal)-DotProduct(p2, edgenormal);
if (DotProduct(impactpoint, edgenormal) > DotProduct(p2, edgenormal))
continue;
CrossProduct(normal, edge2, edgenormal);
if (DotProduct(impactpoint, edgenormal) > DotProduct(p3, edgenormal))
continue;
VectorSubtract(p1, p3, edge3);
CrossProduct(normal, edge3, edgenormal);
if (DotProduct(impactpoint, edgenormal) > DotProduct(p1, edgenormal))
continue;
trace->fraction = frac;
VectorCopy(impactpoint, trace->endpos);
VectorCopy(normal, trace->plane.normal);
/*okay, this is where it hits this plane*/
// trace->endpos[0] = traceinfo.start[0] + frac*(traceinfo.end[0] - traceinfo.start[0]);
// trace->endpos[1] = traceinfo.start[1] + frac*(traceinfo.end[1] - traceinfo.start[1]);
// trace->endpos[2] = traceinfo.start[2] + frac*(traceinfo.end[2] - traceinfo.start[2]);
}
mod = mod->nextsurf;
@ -2307,7 +2401,7 @@ void Mod_ParseQ3SkinFile(char *out, char *surfname, char *modelname, int skinnum
}
#if defined(D3DQUAKE) || defined(GLQUAKE)
shader_t *Mod_LoadSkinFile(shader_t **shaders, char *surfacename, int skinnumber, unsigned char *rawdata, int width, int height, unsigned char *palette)
shader_t *Mod_LoadSkinFile(char *surfacename, int skinnumber, unsigned char *rawdata, int width, int height, unsigned char *palette)
{
shader_t *shader;
char shadername[MAX_QPATH];
@ -2797,7 +2891,7 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran
}
#endif
qboolean Mod_LoadQ1Model (model_t *mod, void *buffer)
qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer)
{
#ifndef SERVERONLY
vec2_t *st_array;
@ -3174,7 +3268,7 @@ static void Q2_LoadSkins(md2_t *pq2inmodel, char *skins)
}
#define MD2_MAX_TRIANGLES 4096
qboolean Mod_LoadQ2Model (model_t *mod, void *buffer)
qboolean QDECL Mod_LoadQ2Model (model_t *mod, void *buffer)
{
#ifndef SERVERONLY
dmd2stvert_t *pinstverts;
@ -3965,7 +4059,7 @@ typedef struct {
} md3Shader_t;
//End of Tenebrae 'assistance'
qboolean Mod_LoadQ3Model(model_t *mod, void *buffer)
qboolean QDECL Mod_LoadQ3Model(model_t *mod, void *buffer)
{
#ifndef SERVERONLY
galiasskin_t *skin;
@ -4294,7 +4388,7 @@ typedef struct zymvertex_s
//this can generate multiple meshes (one for each shader).
//but only one set of transforms are ever generated.
qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer)
qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer)
{
#ifndef SERVERONLY
galiasskin_t *skin;
@ -4483,7 +4577,7 @@ qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer)
skin[j].numshaders = 1; //non-sequenced skins.
skin[j].ofsshaders = shaders;
Mod_LoadSkinFile(shaders, surfname, j, NULL, 0, 0, NULL);
shaders[0] = Mod_LoadSkinFile(surfname, j, NULL, 0, 0, NULL);
}
root[i].ofsskins = skin;
@ -4643,7 +4737,7 @@ typedef struct pskanimkeys_s
} pskanimkeys_t;
qboolean Mod_LoadPSKModel(model_t *mod, void *buffer)
qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer)
{
pskchunk_t *chunk;
unsigned int pos = 0;
@ -5316,7 +5410,7 @@ typedef struct dpmvertex_s
// immediately followed by 1 or more dpmbonevert_t structures
} dpmvertex_t;
qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer)
qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer)
{
#ifndef SERVERONLY
galiasskin_t *skin;
@ -5540,7 +5634,7 @@ qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer)
skin[j].numshaders = 1; //non-sequenced skins.
skin[j].ofsshaders = shaders;
Mod_LoadSkinFile(shaders, mesh->shadername, j, NULL, 0, 0, NULL);
shaders[0] = Mod_LoadSkinFile(mesh->shadername, j, NULL, 0, 0, NULL);
}
m->ofsskins = skin;
@ -6694,7 +6788,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer, char *modname)
#undef EXPECT
}
qboolean Mod_LoadMD5MeshModel(model_t *mod, void *buffer)
qboolean QDECL Mod_LoadMD5MeshModel(model_t *mod, void *buffer)
{
galiasinfo_t *root;
@ -6732,7 +6826,7 @@ clampgroup test/idle1.md5anim
frames test/idle1.md5anim
*/
qboolean Mod_LoadCompositeAnim(model_t *mod, void *buffer)
qboolean QDECL Mod_LoadCompositeAnim(model_t *mod, void *buffer)
{
int i;
@ -6932,3 +7026,36 @@ char *Mod_GetBoneName(struct model_s *model, int bonenum)
return "";
}
#endif //#if defined(D3DQUAKE) || defined(GLQUAKE)
void Alias_Register(void)
{
Mod_RegisterModelFormatMagic(NULL, "Quake1 Model (mdl)", IDPOLYHEADER, Mod_LoadQ1Model);
Mod_RegisterModelFormatMagic(NULL, "Hexen2 Model (mdl)", RAPOLYHEADER, Mod_LoadQ1Model);
#ifdef MD2MODELS
Mod_RegisterModelFormatMagic(NULL, "Quake2 Model (md2)", MD2IDALIASHEADER, Mod_LoadQ2Model);
#endif
#ifdef MD3MODELS
Mod_RegisterModelFormatMagic(NULL, "Quake3 Model (md3)", MD3_IDENT, Mod_LoadQ3Model);
#endif
#ifdef HALFLIFEMODELS
Mod_RegisterModelFormatMagic(NULL, "Half-Life Model (mdl)", (('T'<<24)+('S'<<16)+('D'<<8)+'I'), Mod_LoadHLModel);
#endif
#ifdef ZYMOTICMODELS
Mod_RegisterModelFormatMagic(NULL, "Zymotic Model (zym)", (('O'<<24)+('M'<<16)+('Y'<<8)+'Z'), Mod_LoadZymoticModel);
#endif
#ifdef DPMMODELS
Mod_RegisterModelFormatMagic(NULL, "DarkPlaces Model (dpm)", (('K'<<24)+('R'<<16)+('A'<<8)+'D'), Mod_LoadDarkPlacesModel);
#endif
#ifdef PSKMODELS
Mod_RegisterModelFormatMagic(NULL, "Unreal Interchange Model (psk)", ('A'<<0)+('C'<<8)+('T'<<16)+('R'<<24), Mod_LoadPSKModel);
#endif
#ifdef INTERQUAKEMODELS
Mod_RegisterModelFormatMagic(NULL, "Inter-Quake Model (iqm)", ('I'<<0)+('N'<<8)+('T'<<16)+('E'<<24), Mod_LoadPSKModel);
#endif
#ifdef MD5MODELS
Mod_RegisterModelFormatText(NULL, "MD5 Mesh/Anim (md5mesh)", "MD5Version", Mod_LoadMD5MeshModel);
Mod_RegisterModelFormatText(NULL, "External Anim", "EXTERNALANIM", Mod_LoadCompositeAnim);
#endif
}

View File

@ -161,32 +161,11 @@ void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weight
qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, int surfnum, entity_t *e, qboolean allowskel);
void Alias_FlushCache(void);
void Alias_Shutdown(void);
void Alias_Register(void);
void Mod_DoCRC(model_t *mod, char *buffer, int buffersize);
qboolean Mod_LoadQ1Model (model_t *mod, void *buffer);
#ifdef MD2MODELS
qboolean Mod_LoadQ2Model (model_t *mod, void *buffer);
#endif
#ifdef MD3MODELS
qboolean Mod_LoadQ3Model(model_t *mod, void *buffer);
#endif
#ifdef ZYMOTICMODELS
qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer);
#endif
#ifdef DPMMODELS
qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer);
#endif
#ifdef PSKMODELS
qboolean Mod_LoadPSKModel(model_t *mod, void *buffer);
#endif
#ifdef INTERQUAKEMODELS
qboolean Mod_LoadInterQuakeModel(model_t *mod, void *buffer);
#endif
#ifdef MD5MODELS
qboolean Mod_LoadMD5MeshModel(model_t *mod, void *buffer);
qboolean Mod_LoadCompositeAnim(model_t *mod, void *buffer);
#endif
qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer);
#ifdef MAP_PROC
qboolean Mod_LoadMap_Proc(model_t *mode, void *buffer);
#endif

View File

@ -3809,6 +3809,7 @@ void COM_ParsePlusSets (void)
}
}
void Cvar_DefaultFree(char *str);
/*
================
COM_CheckRegistered
@ -3837,8 +3838,14 @@ void COM_CheckRegistered (void)
newdef = static_registered?"1":"0";
if (strcmp(registered.defaultstr, newdef))
if (strcmp(registered.enginevalue, newdef))
{
if (registered.defaultstr != registered.enginevalue)
{
Cvar_DefaultFree(registered.defaultstr);
registered.defaultstr = NULL;
}
registered.enginevalue = newdef;
registered.defaultstr = newdef;
Cvar_ForceSet(&registered, newdef);
if (static_registered)
@ -4002,7 +4009,9 @@ void COM_Version_f (void)
Con_Printf("Compiled with Cygwin\n");
#endif
#ifdef __GNUC__
#ifdef __clang__
Con_Printf("Compiled with clang version: %i.%i.%i (%s)\n",__clang_major__, __clang_minor__, __clang_patchlevel__, __VERSION__);
#elif defined(__GNUC__)
Con_Printf("Compiled with GCC version: %i.%i.%i (%s)\n",__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, __VERSION__);
#ifdef __OPTIMIZE__
@ -4225,6 +4234,7 @@ void COM_Init (void)
nullentitystate.hexen2flags = SCALE_ORIGIN_ORIGIN;
nullentitystate.colormod[0] = 32;
nullentitystate.colormod[1] = 32;
nullentitystate.colormod[2] = 32;

View File

@ -366,7 +366,7 @@ void Cvar_List_f (void)
}
// print default value
if (listflags & CLF_DEFAULT)
if (cmd->defaultstr && (listflags & CLF_DEFAULT))
Con_Printf(", default \"%s\"", cmd->defaultstr);
// print alternate name
@ -407,6 +407,48 @@ void Cvar_List_f (void)
}
}
void Cvar_LockDefaults_f(void)
{
cvar_group_t *grp;
cvar_t *cmd;
for (grp=cvar_groups ; grp ; grp=grp->next)
{
for (cmd=grp->cvars ; cmd ; cmd=cmd->next)
{
if (cmd->flags & (CVAR_NOSET | CVAR_CHEAT))
continue;
if (strcmp(cmd->string, cmd->defaultstr))
{
if (cmd->defaultstr != cmd->enginevalue)
Cvar_DefaultFree(cmd->defaultstr);
cmd->defaultstr = Cvar_DefaultAlloc(cmd->string);
}
}
}
}
void Cvar_PurgeDefaults_f(void)
{
cvar_group_t *grp;
cvar_t *cmd;
for (grp=cvar_groups ; grp ; grp=grp->next)
{
for (cmd=grp->cvars ; cmd ; cmd=cmd->next)
{
if (!cmd->enginevalue)
continue; //can't reset the cvar's default if its an engine cvar.
if (cmd->flags & CVAR_NOSET)
continue;
if (cmd->defaultstr != cmd->enginevalue)
{
Cvar_DefaultFree(cmd->defaultstr);
cmd->defaultstr = cmd->enginevalue;
}
}
}
}
#define CRF_ALTNAME 0x1
void Cvar_Reset_f (void)
{
@ -416,6 +458,8 @@ void Cvar_Reset_f (void)
char *var;
char *search, *gsearch;
char strtmp[512];
char *resetval;
char *pendingval;
search = gsearch = NULL;
exclflags = 0;
@ -479,9 +523,9 @@ void Cvar_Reset_f (void)
if (gsearch)
Q_strlwr(gsearch);
if (!strcmp(search, "*"))
if (search && !strcmp(search, "*"))
search = NULL;
if (!strcmp(gsearch, "*"))
if (gsearch && !strcmp(gsearch, "*"))
gsearch = NULL;
for (grp=cvar_groups ; grp ; grp=grp->next)
@ -526,8 +570,19 @@ void Cvar_Reset_f (void)
if ((cmd->flags & CVAR_NOSET) && !search)
continue;
// reset cvar to default
Cvar_Set(cmd, cmd->defaultstr);
// reset cvar to default only if its okay to do so
if (cmd->defaultstr)
resetval = cmd->defaultstr;
else if (cmd->enginevalue)
resetval = cmd->enginevalue;
else
continue; //no idea what to reset it to.
pendingval = cmd->string;
if (cmd->latched_string)
pendingval = cmd->latched_string;
if (strcmp(resetval, pendingval))
Cvar_Set(cmd, resetval);
}
}
}
@ -938,7 +993,7 @@ void Cvar_Free(cvar_t *tbf)
}
unlinked:
Z_Free(tbf->string);
if (tbf->flags & CVAR_FREEDEFAULT)
if (tbf->defaultstr != tbf->enginevalue)
Cvar_DefaultFree(tbf->defaultstr);
if (tbf->latched_string)
Z_Free(tbf->latched_string);
@ -964,8 +1019,12 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname)
if (variable->defaultstr)
initial = variable->defaultstr;
else
else if (variable->enginevalue)
initial = variable->enginevalue;
else if (variable->string)
initial = variable->string;
else
initial = "";
// check to see if it has already been defined
old = Cvar_FindVar (variable->name);
@ -987,7 +1046,7 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname)
variable->string = (char*)Z_Malloc (1);
//cheat prevention - engine set default is the one that stays.
if (variable->flags & CVAR_FREEDEFAULT)
if (initial != variable->enginevalue)
variable->defaultstr = Cvar_DefaultAlloc(initial);
else
variable->defaultstr = initial;
@ -1031,7 +1090,7 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname)
variable->string = NULL;
if (variable->flags & CVAR_FREEDEFAULT)
if (initial != variable->enginevalue)
variable->defaultstr = Cvar_DefaultAlloc(initial);
else
variable->defaultstr = initial;
@ -1065,7 +1124,7 @@ cvar_t *Cvar_Get(const char *name, const char *defaultvalue, int flags, const ch
var->name = (char *)(var+1);
strcpy(var->name, name);
var->string = (char*)defaultvalue;
var->flags = flags|CVAR_POINTER|CVAR_FREEDEFAULT|CVAR_USERCREATED;
var->flags = flags|CVAR_POINTER|CVAR_USERCREATED;
if (!Cvar_Register(var, group))
return NULL;
@ -1147,16 +1206,18 @@ qboolean Cvar_Command (int level)
Con_Printf ("\"%s\" is %s\n", v->name, COM_QuotedString(v->latched_string, buffer, sizeof(buffer)));
Con_Printf ("Effective value is %s\n", COM_QuotedString(v->string, buffer, sizeof(buffer)));
}
Con_Printf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer)));
if (v->defaultstr)
Con_Printf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer)));
}
else
{
if (!strcmp(v->string, v->defaultstr))
if (v->defaultstr && !strcmp(v->string, v->defaultstr))
Con_Printf ("\"%s\" is %s (default)\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer)));
else
{
Con_Printf ("\"%s\" is %s\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer)));
Con_Printf("Default: %s\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer)));
if (v->defaultstr)
Con_Printf("Default: %s\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer)));
}
}
return true;
@ -1184,7 +1245,7 @@ qboolean Cvar_Command (int level)
{
if (Cmd_FromGamecode())
{
if (!strcmp(v->defaultstr, str)) //returning to default
if (!v->defaultstr || !strcmp(v->defaultstr, str)) //returning to default
{
v->flags &= ~CVAR_SERVEROVERRIDE;
if (v->latched_string)
@ -1200,7 +1261,7 @@ qboolean Cvar_Command (int level)
}
else if (Cmd_FromGamecode())
{//it's not latched yet
if (strcmp(v->defaultstr, str))
if (v->defaultstr && strcmp(v->defaultstr, str))
{ //lock the cvar, unless it's going to it's default value.
Cvar_LockFromServer(v, str);
return true;
@ -1325,7 +1386,7 @@ void Cvar_Shutdown(void)
var = cvar_groups->cvars;
cvar_groups->cvars = var->next;
if (var->flags & CVAR_FREEDEFAULT)
if (var->defaultstr != var->enginevalue)
{
Cvar_DefaultFree(var->defaultstr);
var->defaultstr = NULL;

View File

@ -58,24 +58,25 @@ interface from being ambiguous.
typedef struct cvar_s
{
//must match q2's definition
char *name;
char *string;
char *latched_string; // for CVAR_LATCH vars
int flags;
int modified; // increased each time the cvar is changed
float value;
struct cvar_s *next;
char *name;
char *string;
char *latched_string; // for CVAR_LATCH vars
unsigned int flags;
int modified; // increased each time the cvar is changed
float value;
struct cvar_s *next;
//free style :)
char *name2;
char *name2;
void (*callback) (struct cvar_s *var, char *oldvalue);
char *description;
char *defaultstr; //default
void (*callback) (struct cvar_s *var, char *oldvalue);
char *description;
char *enginevalue; //when changing manifest dir, the cvar will be reset to this value. never freed.
char *defaultstr; //this is the current mod's default value. set on first update.
int ival;
qbyte restriction;
int ival;
qbyte restriction;
#ifdef HLSERVER
struct hlcvar_s *hlcvar;
@ -122,10 +123,10 @@ typedef struct cvar_group_s
//freestyle
#define CVAR_POINTER (1<<5) // q2 style. May be converted to q1 if needed. These are often specified on the command line and then converted into q1 when registered properly.
#define CVAR_FREEDEFAULT (1<<6) //the default string was malloced/needs to be malloced, free on unregister
#define CVAR_UNUSED (1<<6) //the default string was malloced/needs to be malloced, free on unregister
#define CVAR_NOTFROMSERVER (1<<7) // the console will ignore changes to cvars if set at from the server or any gamecode. This is to protect against security flaws - like qterm
#define CVAR_USERCREATED (1<<8) //write a 'set' or 'seta' in front of the var name.
#define CVAR_CHEAT (1<<9) //latch to the default, unless cheats are enabled.
#define CVAR_CHEAT (1<<9) //latch to the default, unless cheats are enabled.
#define CVAR_SEMICHEAT (1<<10) //if strict ruleset, force to 0/blank.
#define CVAR_RENDERERLATCH (1<<11) //requires a vid_restart to reapply.
#define CVAR_SERVEROVERRIDE (1<<12) //the server has overridden out local value - should probably be called SERVERLATCH
@ -135,6 +136,8 @@ typedef struct cvar_group_s
#define CVAR_SHADERSYSTEM (1<<16) //change flushes shaders.
#define CVAR_TELLGAMECODE (1<<17) //tells the gamecode when it has changed, does not prevent changing, added as an optimisation
#define CVAR_CONFIGDEFAULT (1<<18) //this cvar's default value has been changed to match a config.
#define CVAR_LASTFLAG CVAR_SHADERSYSTEM
#define CVAR_LATCHMASK (CVAR_LATCH|CVAR_RENDERERLATCH|CVAR_SERVEROVERRIDE|CVAR_CHEAT|CVAR_SEMICHEAT) //you're only allowed one of these.

View File

@ -17,6 +17,7 @@
#endif
hashtable_t filesystemhash;
qboolean blockcache = true;
qboolean com_fschanged = true;
static unsigned int fs_restarts;
extern cvar_t com_fs_cache;
@ -339,7 +340,7 @@ static void FS_Manifest_ParseTokens(ftemanifest_t *man)
char *newdir = Cmd_Argv(1);
//reject various evil path arguments.
if (!*newdir || strchr(newdir, '\n') || strchr(newdir, '\r') || strchr(newdir, '.') || strchr(newdir, ':') || strchr(newdir, '?') || strchr(newdir, '*') || strchr(newdir, '/') || strchr(newdir, '\\') || strchr(newdir, '$'))
if (!*newdir || strchr(newdir, '\n') || strchr(newdir, '\r') || !strcmp(newdir, ".") || !strcmp(newdir, "..") || strchr(newdir, ':') || strchr(newdir, '/') || strchr(newdir, '\\') || strchr(newdir, '$'))
{
Con_Printf("Illegal path specified: %s\n", newdir);
}
@ -798,7 +799,7 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation
goto fail;
}
if (com_fs_cache.ival)
if (com_fs_cache.ival && !blockcache)
{
if (com_fschanged)
FS_RebuildFSHash();
@ -1100,7 +1101,7 @@ static const char *FS_GetCleanPath(const char *pattern, char *outbuf, int outlen
Q_strncpyz(outbuf, pattern, outlen);
pattern = outbuf;
Con_Printf("Warning: \\ characters in filename %s\n", pattern);
Con_DPrintf("Warning: \\ characters in filename %s\n", pattern);
while((s = strchr(pattern, '\\')))
{
*s = '/';
@ -1615,12 +1616,19 @@ static int QDECL FS_AddWildDataFiles (const char *descriptor, int size, void *vp
newpak = FS_GetOldPath(param->oldpaths, pakfile);
if (!newpak)
{
fs_finds++;
if (!funcs->FindFile(funcs, &loc, descriptor, NULL))
return true; //not found..
vfs = funcs->OpenVFS(funcs, &loc, "rb");
if (!vfs)
return true;
if (param->OpenNew == VFSOS_OpenPath)
{
vfs = NULL;
}
else
{
fs_finds++;
if (!funcs->FindFile(funcs, &loc, descriptor, NULL))
return true; //not found..
vfs = funcs->OpenVFS(funcs, &loc, "rb");
if (!vfs)
return true;
}
newpak = param->OpenNew (vfs, pakfile);
if (!newpak)
{
@ -1815,7 +1823,7 @@ void COM_RefreshFSCache_f(void)
void COM_FlushFSCache(void)
{
searchpath_t *search;
if (com_fs_cache.ival != 2)
if (com_fs_cache.ival && com_fs_cache.ival != 2)
{
for (search = com_searchpaths ; search ; search = search->next)
{
@ -2105,7 +2113,7 @@ void COM_Gamedir (const char *dir)
/*stuff that makes dp-only mods work a bit better*/
#define DPCOMPAT QCFG "set _cl_playermodel \"\"\n set dpcompat_set 1\n set dpcompat_trailparticles 1\nset dpcompat_corruptglobals 1\nset vid_pixelheight 1\n"
/*nexuiz/xonotic has a few quirks/annoyances...*/
#define NEXCFG DPCOMPAT "set r_particlesdesc effectinfo\nset sv_maxairspeed \"400\"\nset sv_jumpvelocity 270\nset sv_mintic \"0.01\"\ncl_nolerp 0\npr_enable_uriget 0\n"
#define NEXCFG DPCOMPAT "set r_particlesdesc effectinfo\nset sv_bigcoords 1\nset sv_maxairspeed \"400\"\nset sv_jumpvelocity 270\nset sv_mintic \"0.01\"\ncl_nolerp 0\npr_enable_uriget 0\n"
/*some modern non-compat settings*/
#define DMFCFG "set com_parseutf8 1\npm_airstep 1\nsv_demoExtensions 1\n"
/*set some stuff so our regular qw client appears more like hexen2*/
@ -2166,13 +2174,16 @@ const gamemode_info_t gamemode_info[] = {
{"-quake4", "q4", "FTE-Quake4", {"q4base/pak00.pk4"}, NULL, {"q4base", "fteq4"}, "Quake 4"},
{"-et", "et", "FTE-EnemyTerritory", {"etmain/pak0.pk3"}, NULL, {"etmain", "fteet"}, "Wolfenstein - Enemy Territory"},
{"-jk2", "jk2", "FTE-JK2", {"base/assets0.pk3"}, NULL, {"base", "fte"}, "Jedi Knight II: Jedi Outcast"},
{"-warsow", "warsow", "FTE-Warsow", {"basewsw/pak0.pk3"}, NULL, {"basewsw", "fte"}, "Warsow"},
{"-jk2", "jk2", "FTE-JK2", {"base/assets0.pk3"}, NULL, {"base", "ftejk2"}, "Jedi Knight II: Jedi Outcast"},
{"-warsow", "warsow", "FTE-Warsow", {"basewsw/pak0.pk3"}, NULL, {"basewsw", "ftewsw"}, "Warsow"},
{"-doom", "doom", "FTE-Doom", {"doom.wad"}, NULL, {"*doom.wad", "ftedoom"}, "Doom"},
{"-doom2", "doom2", "FTE-Doom2", {"doom2.wad"}, NULL, {"*doom2.wad", "ftedoom"}, "Doom2"},
{"-doom3", "doom3", "FTE-Doom3", {"doom3.wad"}, NULL, {"*doom2.wad", "ftedoom"}, "Doom2"},
//for the luls
{"-diablo2", NULL, "FTE-Diablo2", {"d2music.mpq"}, NULL, {"**.mpq", "fted2"}, "Diablo 2"},
{NULL}
};
@ -2333,9 +2344,35 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
{
if (fs_manifest->gamepath[i].path && fs_manifest->gamepath[i].base)
{
FS_AddGameDirectory(&oldpaths, fs_manifest->gamepath[i].path, va("%s%s", com_quakedir, fs_manifest->gamepath[i].path), reloadflags);
if (*com_homedir)
FS_AddGameDirectory(&oldpaths, fs_manifest->gamepath[i].path, va("%s%s", com_homedir, fs_manifest->gamepath[i].path), reloadflags);
//paths with '*' actually result in loading packages without an actual gamedir. note that this does not imply that we can write anything.
if (*fs_manifest->gamepath[i].path == '*')
{
int j;
searchpathfuncs_t *handle = VFSOS_OpenPath(NULL, com_quakedir);
searchpath_t *search = (searchpath_t*)Z_Malloc (sizeof(searchpath_t));
search->flags = 0;
search->handle = handle;
Q_strncpyz(search->purepath, "", sizeof(search->purepath));
Q_strncpyz(search->logicalpath, com_quakedir, sizeof(search->logicalpath));
for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++)
{
if (!searchpathformats[j].extension || !searchpathformats[j].OpenNew || !searchpathformats[j].loadscan)
continue;
if (reloadflags & (1<<j))
{
FS_AddDataFiles(&oldpaths, search->purepath, search->logicalpath, search, searchpathformats[j].extension, searchpathformats[j].OpenNew);
}
}
handle->ClosePath(handle);
Z_Free(search);
}
else
{
FS_AddGameDirectory(&oldpaths, fs_manifest->gamepath[i].path, va("%s%s", com_quakedir, fs_manifest->gamepath[i].path), reloadflags);
if (*com_homedir)
FS_AddGameDirectory(&oldpaths, fs_manifest->gamepath[i].path, va("%s%s", com_homedir, fs_manifest->gamepath[i].path), reloadflags);
}
}
}
com_base_searchpaths = com_searchpaths;
@ -2343,9 +2380,15 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
{
if (fs_manifest->gamepath[i].path && !fs_manifest->gamepath[i].base)
{
FS_AddGameDirectory(&oldpaths, fs_manifest->gamepath[i].path, va("%s%s", com_quakedir, fs_manifest->gamepath[i].path), reloadflags);
if (*com_homedir)
FS_AddGameDirectory(&oldpaths, fs_manifest->gamepath[i].path, va("%s%s", com_homedir, fs_manifest->gamepath[i].path), reloadflags);
if (*fs_manifest->gamepath[i].path == '*')
{
}
else
{
FS_AddGameDirectory(&oldpaths, fs_manifest->gamepath[i].path, va("%s%s", com_quakedir, fs_manifest->gamepath[i].path), reloadflags);
if (*com_homedir)
FS_AddGameDirectory(&oldpaths, fs_manifest->gamepath[i].path, va("%s%s", com_homedir, fs_manifest->gamepath[i].path), reloadflags);
}
}
}
@ -2553,6 +2596,20 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
if (!strcmp(gamename, "quake"))
{
char *prefix[] =
{
"c:/quake/", //quite a lot of people have it in c:\quake, as that's the default install location from the quake cd.
"c:/games/quake/", //personally I use this
#ifdef _WIN64
//quite a few people have nquake installed. we need to an api function to read the directory for non-english-windows users.
va("%s/nQuake/", getenv("%ProgramFiles(x86)%")), //64bit builds should look in both places
va("%s/nQuake/", getenv("%ProgramFiles%")), //
#else
va("%s/nQuake/", getenv("%ProgramFiles%")), //32bit builds will get the x86 version anyway.
#endif
NULL
};
int i;
FILE *f;
//try and find it via steam
@ -2563,13 +2620,17 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
return true;
//well, okay, so they don't have quake installed from steam.
//quite a lot of people have it in c:\quake, as that's the default install location from the quake cd.
if ((f = fopen("c:/quake/quake.exe", "rb")))
//check various 'unadvertised' paths
for (i = 0; prefix[i]; i++)
{
//HAHAHA! Found it!
fclose(f);
Q_strncpyz(basepath, "c:/quake", basepathlen);
return true;
char syspath[MAX_OSPATH];
Q_snprintfz(syspath, sizeof(syspath), "%sid1/pak0.pak", prefix[i]);
if ((f = fopen("c:/quake/quake.exe", "rb")))
{
fclose(f);
Q_strncpyz(basepath, prefix[i], sizeof(basepath));
return true;
}
}
}
@ -2941,6 +3002,25 @@ static void FS_StartupWithGame(int gamenum)
}
#endif
static qboolean FS_DirHasAPackage(char *basedir, ftemanifest_t *man)
{
int j;
vfsfile_t *f;
for (j = 0; j < sizeof(fs_manifest->package) / sizeof(fs_manifest->package[0]); j++)
{
if (!man->package[j].path)
continue;
f = VFSOS_Open(va("%s%s", basedir, man->package[j].path), "rb");
if (f)
{
VFS_CLOSE(f);
return true;
}
}
return false;
}
//just check each possible file, see if one is there.
static qboolean FS_DirHasGame(char *basedir, int gameidx)
{
@ -2999,10 +3079,12 @@ static int FS_IdentifyDefaultGame(char *newbase, int sizeof_newbase, qboolean fi
//use the game based on an exe name over the filesystem one (could easily have multiple fs path matches).
if (gamenum == -1)
{
char *ev, *v0 = COM_SkipPath(com_argv[0]);
for (i = 0; gamemode_info[i].argname; i++)
{
char *ev = COM_SkipPath(com_argv[0]);
ev = strstr(ev, gamemode_info[i].exename);
if (!gamemode_info[i].exename)
continue;
ev = strstr(v0, gamemode_info[i].exename);
if (ev && (!strchr(ev, '\\') && !strchr(ev, '/')))
gamenum = i;
}
@ -3231,6 +3313,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs)
char newbasedir[MAX_OSPATH];
qboolean fixedbasedir;
qboolean reloadconfigs = false;
qboolean builtingame = false;
flocation_t loc;
//if any of these files change location, the configs will be re-execed.
@ -3277,6 +3360,8 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs)
}
fs_manifest = man;
blockcache = true;
if (man->installation && *man->installation)
{
for (i = 0; gamemode_info[i].argname; i++)
@ -3309,6 +3394,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs)
man->defaultexec = Z_StrDup(gamemode_info[i].customexec);
}
builtingame = true;
if (!fixedbasedir && !FS_DirHasGame(newbasedir, i))
if (Sys_FindGameData(man->formalname, man->installation, realpath, sizeof(realpath)))
Q_strncpyz (newbasedir, realpath, sizeof(newbasedir));
@ -3316,6 +3402,11 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs)
}
}
}
if (!builtingame && !fixedbasedir && !FS_DirHasAPackage(newbasedir, man))
if (Sys_FindGameData(man->formalname, man->installation, realpath, sizeof(realpath)))
Q_strncpyz (newbasedir, realpath, sizeof(newbasedir));
Q_strncpyz (com_quakedir, newbasedir, sizeof(com_quakedir));
//make sure it has a trailing slash, or is empty. woo.
FS_CleanDir(com_quakedir, sizeof(com_quakedir));
@ -3366,6 +3457,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs)
#endif
}
}
blockcache = false;
}
COM_Effectinfo_Clear();
@ -3587,6 +3679,7 @@ void FS_RegisterDefaultFileSystems(void)
/*for systems that have case sensitive paths, also include *.PAK */
FS_RegisterFileSystemType(NULL, "PAK", FSPAK_LoadArchive, true);
#endif
FS_RegisterFileSystemType(NULL, "pk3dir", VFSOS_OpenPath, true);
#ifdef AVAIL_ZLIB
FS_RegisterFileSystemType(NULL, "pk3", FSZIP_LoadArchive, true);
FS_RegisterFileSystemType(NULL, "pk4", FSZIP_LoadArchive, true);

View File

@ -138,7 +138,8 @@ vfsfile_t *QDECL VFSW32_Open(const char *osname, const char *mode)
if (h == INVALID_HANDLE_VALUE)
return NULL;
if (write || append || text)
fsize = GetFileSize(h, NULL);
if (write || append || text || fsize > 1024*1024*5)
{
fsize = 0;
mh = INVALID_HANDLE_VALUE;
@ -150,7 +151,6 @@ vfsfile_t *QDECL VFSW32_Open(const char *osname, const char *mode)
}
else
{
fsize = GetFileSize(h, NULL);
mh = CreateFileMapping(h, NULL, PAGE_READONLY, 0, 0, NULL);
if (mh == INVALID_HANDLE_VALUE)
mmap = NULL;

View File

@ -4217,7 +4217,7 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c
}
#ifdef TERRAIN
im->terrain = Mod_LoadTerrainInfo(im, loadname);
im->terrain = Mod_LoadTerrainInfo(im, loadname, false);
#endif
return &map_cmodels[0];
@ -6020,7 +6020,7 @@ unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p)
int map_checksum;
qboolean Mod_LoadQ2BrushModel (model_t *mod, void *buffer)
qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer)
{
mod->fromgame = fg_quake2;
return CM_LoadMap(mod->name, buffer, true, &map_checksum) != NULL;

View File

@ -1041,6 +1041,26 @@ void Matrix4x4_RM_CreateTranslate (float *out, float x, float y, float z)
out[15] = 1;
}
void Matrix4x4_CM_LightMatrixFromAxis(float *modelview, const vec3_t px, const vec3_t py, const vec3_t pz, const vec3_t org)
{
modelview[ 0] = px[0];
modelview[ 1] = py[0];
modelview[ 2] = pz[0];
modelview[ 3] = 0;
modelview[ 4] = px[1];
modelview[ 5] = py[1];
modelview[ 6] = pz[1];
modelview[ 7] = 0;
modelview[ 8] = px[2];
modelview[ 9] = py[2];
modelview[10] = pz[2];
modelview[11] = 0;
modelview[12] = -(px[0]*org[0] + px[1]*org[1] + px[2]*org[2]);
modelview[13] = -(py[0]*org[0] + py[1]*org[1] + py[2]*org[2]);
modelview[14] = -(pz[0]*org[0] + pz[1]*org[1] + pz[2]*org[2]);
modelview[15] = 1;
}
void Matrix4x4_CM_ModelViewMatrixFromAxis(float *modelview, const vec3_t pn, const vec3_t right, const vec3_t up, const vec3_t vieworg)
{
float tempmat[16];

View File

@ -164,6 +164,7 @@ void Matrix4x4_CM_ModelMatrixFromAxis (float *modelview, const vec3_t pn, const
void Matrix4x4_CM_ModelMatrix(float *modelview, vec_t x, vec_t y, vec_t z, vec_t pitch, vec_t yaw, vec_t roll, vec_t scale);
void Matrix4x4_CM_ModelViewMatrix (float *modelview, const vec3_t viewangles, const vec3_t vieworg);
void Matrix4x4_CM_ModelViewMatrixFromAxis (float *modelview, const vec3_t pn, const vec3_t right, const vec3_t up, const vec3_t vieworg);
void Matrix4x4_CM_LightMatrixFromAxis(float *modelview, const vec3_t px, const vec3_t py, const vec3_t pz, const vec3_t vieworg); //
void Matrix4_CreateFromQuakeEntity (float *matrix, float x, float y, float z, float pitch, float yaw, float roll, float scale);
void Matrix4_Multiply (const float *a, const float *b, float *out);
void Matrix3x4_Multiply(const float *a, const float *b, float *out);

View File

@ -5514,6 +5514,7 @@ qboolean QDECL ICE_Set(struct icestate_s *con, char *prop, char *value)
int codec = atoi(prop+5);
if (codec < 96 || codec > 127)
return false;
codec -= 96;
#if !defined(SERVERONLY) && defined(VOICECHAT)
if (!S_Voip_RTP_CodecOkay(value))
#endif
@ -5522,7 +5523,6 @@ qboolean QDECL ICE_Set(struct icestate_s *con, char *prop, char *value)
con->codec[codec] = NULL;
return false;
}
codec -= 96;
Z_Free(con->codec[codec]);
con->codec[codec] = Z_StrDup(value);
}

View File

@ -129,7 +129,7 @@ int PM_SlideMove (void)
for (i=0 ; i<3 ; i++)
end[i] = pmove.origin[i] + time_left * pmove.velocity[i];
trace = PM_PlayerTrace (pmove.origin, end);
trace = PM_PlayerTrace (pmove.origin, end, MASK_PLAYERSOLID);
if (trace.startsolid || trace.allsolid)
{ // entity is trapped in another solid
@ -272,7 +272,7 @@ int PM_StepSlideMove (qboolean in_air)
org = (-DotProduct(pmove.gravitydir, originalvel) < 0) ? pmove.origin : original;
VectorMA (org, movevars.stepheight, pmove.gravitydir, dest);
trace = PM_PlayerTrace (org, dest);
trace = PM_PlayerTrace (org, dest, MASK_PLAYERSOLID);
if (trace.fraction == 1 || -DotProduct(pmove.gravitydir, trace.plane.normal) < MIN_STEP_NORMAL)
return blocked;
@ -291,7 +291,7 @@ int PM_StepSlideMove (qboolean in_air)
// move up a stair height
VectorMA (pmove.origin, -stepsize, pmove.gravitydir, dest);
trace = PM_PlayerTrace (pmove.origin, dest);
trace = PM_PlayerTrace (pmove.origin, dest, MASK_PLAYERSOLID);
if (!trace.startsolid && !trace.allsolid)
{
VectorCopy (trace.endpos, pmove.origin);
@ -304,7 +304,7 @@ int PM_StepSlideMove (qboolean in_air)
// press down the stepheight
VectorMA (pmove.origin, stepsize, pmove.gravitydir, dest);
trace = PM_PlayerTrace (pmove.origin, dest);
trace = PM_PlayerTrace (pmove.origin, dest, MASK_PLAYERSOLID);
if (trace.fraction != 1 && -DotProduct(pmove.gravitydir, trace.plane.normal) < MIN_STEP_NORMAL)
goto usedown;
if (!trace.startsolid && !trace.allsolid)
@ -396,7 +396,7 @@ void PM_Friction (void)
start[1] = stop[1] = pmove.origin[1] + pmove.velocity[1]/speed*16;
start[2] = pmove.origin[2] + player_mins[2];
stop[2] = start[2] - 34;
trace = PM_PlayerTrace (start, stop);
trace = PM_PlayerTrace (start, stop, MASK_PLAYERSOLID);
if (trace.fraction == 1)
friction *= 2;
@ -608,7 +608,7 @@ void PM_LadderMove (void)
// assume it is a stair or a slope, so press down from stepheight above
VectorMA (pmove.origin, frametime, pmove.velocity, dest);
VectorMA(dest, -(movevars.stepheight + 1), pmove.gravitydir, start);
trace = PM_PlayerTrace (start, dest);
trace = PM_PlayerTrace (start, dest, MASK_PLAYERSOLID);
if (!trace.startsolid && !trace.allsolid) // FIXME: check steep slope?
{ // walked up the step
VectorCopy (trace.endpos, pmove.origin);
@ -749,7 +749,7 @@ void PM_CategorizePosition (void)
}
else
{
trace = PM_PlayerTrace (pmove.origin, point);
trace = PM_PlayerTrace (pmove.origin, point, MASK_PLAYERSOLID);
if (trace.fraction == 1 || -DotProduct(pmove.gravitydir, trace.plane.normal) < MIN_STEP_NORMAL)
pmove.onground = false;
else
@ -829,7 +829,7 @@ void PM_CategorizePosition (void)
VectorMA (pmove.origin, 24, flatforward, fwd1);
//if we hit a wall when going forwards and we are in a ladder region, then we are on a ladder.
t = PM_PlayerTrace(pmove.origin, fwd1);
t = PM_PlayerTrace(pmove.origin, fwd1, MASK_PLAYERSOLID);
if (t.fraction < 1)
{
pmove.onladder = true;

View File

@ -119,6 +119,6 @@ int PM_ExtraBoxContents (vec3_t p); //Peeks for HL-style water.
int PM_PointContents (vec3_t point);
qboolean PM_TestPlayerPosition (vec3_t point);
#ifndef __cplusplus
struct trace_s PM_PlayerTrace (vec3_t start, vec3_t stop);
struct trace_s PM_PlayerTrace (vec3_t start, vec3_t stop, unsigned int solidmask);
#endif

View File

@ -282,6 +282,9 @@ qboolean PM_TestPlayerPosition (vec3_t pos)
if (pe->nonsolid)
continue;
if (pe->forcecontentsmask && !(pe->forcecontentsmask & MASK_PLAYERSOLID))
continue;
// get the clipping hull
if (pe->model)
{
@ -297,7 +300,7 @@ qboolean PM_TestPlayerPosition (vec3_t pos)
hull = PM_HullForBox (mins, maxs);
VectorSubtract(pos, pe->origin, mins);
if (Q1BSP_HullPointContents(hull, mins) & FTECONTENTS_SOLID)
if (Q1BSP_HullPointContents(hull, mins) & MASK_PLAYERSOLID)
return false;
}
}
@ -310,7 +313,7 @@ qboolean PM_TestPlayerPosition (vec3_t pos)
PM_PlayerTrace
================
*/
trace_t PM_PlayerTrace (vec3_t start, vec3_t end)
trace_t PM_PlayerTrace (vec3_t start, vec3_t end, unsigned int solidmask)
{
trace_t trace, total;
int i;
@ -330,6 +333,8 @@ trace_t PM_PlayerTrace (vec3_t start, vec3_t end)
continue;
if (pe->info == pmove.skipent)
continue;
if (pe->forcecontentsmask && !(pe->forcecontentsmask & solidmask))
continue;
if (!pe->model || pe->model->needload)
{
@ -377,5 +382,5 @@ trace_t PM_TraceLine (vec3_t start, vec3_t end)
{
VectorClear(player_mins);
VectorClear(player_maxs);
return PM_PlayerTrace(start, end);
return PM_PlayerTrace(start, end, MASK_PLAYERSOLID);
}

View File

@ -1431,6 +1431,7 @@ typedef struct q1usercmd_s
#define SCALE_ORIGIN_CENTER 0 // Scaling origin at object center
#define SCALE_ORIGIN_BOTTOM 32 // Scaling origin at object bottom
#define SCALE_ORIGIN_TOP 64 // Scaling origin at object top
#define SCALE_ORIGIN_ORIGIN (64|32) // Scaling origin at object origin
#define DRF_TRANSLUCENT 128

View File

@ -739,19 +739,29 @@ int Q1BSP_HullPointContents(hull_t *hull, vec3_t p)
unsigned int Q1BSP_PointContents(model_t *model, vec3_t axis[3], vec3_t point)
{
int contents;
if (axis)
{
vec3_t transformed;
transformed[0] = DotProduct(point, axis[0]);
transformed[1] = DotProduct(point, axis[1]);
transformed[2] = DotProduct(point, axis[2]);
return Q1BSP_HullPointContents(&model->hulls[0], transformed);
return Q1BSP_PointContents(model, NULL, transformed);
}
if (!model->firstmodelsurface)
else
{
return Q1BSP_TranslateContents(Q1_ModelPointContents(model->nodes, point));
if (!model->firstmodelsurface)
{
contents = Q1BSP_TranslateContents(Q1_ModelPointContents(model->nodes, point));
}
else
contents = Q1BSP_HullPointContents(&model->hulls[0], point);
}
return Q1BSP_HullPointContents(&model->hulls[0], point);
#ifdef TERRAIN
if (model->terrain)
contents |= Heightmap_PointContents(model, NULL, point);
#endif
return contents;
}
void Q1BSP_LoadBrushes(model_t *model)

View File

@ -592,6 +592,7 @@ void Cache_Flush(void)
#ifndef SERVERONLY
S_Purge(false);
#endif
Mod_Purge(MP_FLUSH);
}
static void Hunk_Print_f (void)

View File

@ -1,6 +1,9 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "FTEQuake", "..\setup\setup.vdproj", "{E0EE8B50-3A75-42A9-B80A-787675979B0C}"
ProjectSection(ProjectDependencies) = postProject
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "botlib", "botlib.vcproj", "{0018E098-B12A-4E4D-9B22-6772DA287080}"
EndProject
@ -387,7 +390,7 @@ Global
{72269FEE-293D-40BC-A7AE-E429F4496869}.Debug|x64.ActiveCfg = Debug|Win32
{72269FEE-293D-40BC-A7AE-E429F4496869}.GLDebug|Win32.ActiveCfg = Debug|Win32
{72269FEE-293D-40BC-A7AE-E429F4496869}.GLDebug|Win32.Build.0 = Debug|Win32
{72269FEE-293D-40BC-A7AE-E429F4496869}.GLDebug|x64.ActiveCfg = Debug|Win32
{72269FEE-293D-40BC-A7AE-E429F4496869}.GLDebug|x64.ActiveCfg = Debug|x64
{72269FEE-293D-40BC-A7AE-E429F4496869}.GLRelease|Win32.ActiveCfg = Release|Win32
{72269FEE-293D-40BC-A7AE-E429F4496869}.GLRelease|Win32.Build.0 = Release|Win32
{72269FEE-293D-40BC-A7AE-E429F4496869}.GLRelease|x64.ActiveCfg = Release|Win32
@ -500,7 +503,6 @@ Global
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.D3DRelease|x64.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.D3DRelease|x64.Build.0 = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug Dedicated Server|Win32.ActiveCfg = Debug Dedicated Server|Win32
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug Dedicated Server|Win32.Build.0 = Debug Dedicated Server|Win32
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug Dedicated Server|x64.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug Dedicated Server|x64.Build.0 = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug|Win32.ActiveCfg = Debug Dedicated Server|x64

View File

@ -1954,7 +1954,7 @@ void BE_GenPolyBatches(batch_t **batches)
}
}
void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches);
model_t *Mod_LoadModel (model_t *mod, qboolean crash);
void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode)
{
int i;
@ -2010,7 +2010,10 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
if (!ent->model)
continue;
if (ent->model->needload)
continue;
{
if (!Mod_LoadModel(ent->model, false))
continue;
}
if (cl.lerpents && (cls.allow_anyparticles)) //allowed or static
{

View File

@ -6,7 +6,7 @@ void DumpGLState(void);
#ifdef GLQUAKE
#define r_refract_fboival gl_config.ext_framebuffer_objects
#define r_refract_fboival (gl_config.ext_framebuffer_objects && r_refract_fbo.ival)
#include "glquake.h"
#include "shader.h"
@ -28,6 +28,7 @@ void DumpGLState(void);
extern cvar_t gl_overbright;
extern cvar_t gl_ati_truform;
extern cvar_t r_wireframe;
extern cvar_t r_refract_fbo;
static const char LIGHTPASS_SHADER[] = "\
{\n\
@ -87,6 +88,7 @@ struct {
const shader_t *depthnormshader;
texid_t tex_normals;
texid_t tex_diffuse;
int fbo_current; //the one currently being rendered to
int fbo_diffuse;
int rb_depth;
int rb_stencil;
@ -957,7 +959,7 @@ void R_IBrokeTheArrays(void)
#ifdef RTLIGHTS
//called from gl_shadow
void GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, float shadowscale)
int GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, float shadowscale)
{
extern cvar_t r_shadow_shadowmapping_bias;
extern cvar_t r_shadow_shadowmapping_nearclip;
@ -988,6 +990,8 @@ void GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, f
// qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
BE_SelectMode(BEM_DEPTHONLY);
return shaderstate.fbo_current;
}
#endif
@ -3358,9 +3362,9 @@ static qboolean GLBE_RegisterLightShader(int mode)
if (!shaderstate.inited_shader_light[mode])
{
char *name = va("rtlight%s%s%s",
(mode & (1u<<LSHADER_SMAP))?"#PCF":"",
(mode & (1u<<LSHADER_SPOT))?"#SPOT":"",
(mode & (1u<<LSHADER_CUBE))?"#CUBE":"");
(mode & LSHADER_SMAP)?"#PCF":"",
(mode & LSHADER_SPOT)?"#SPOT":"",
(mode & LSHADER_CUBE)?"#CUBE":"");
shaderstate.inited_shader_light[mode] = true;
shaderstate.shader_light[mode] = R_RegisterCustom(name, SUF_NONE, Shader_LightPass, NULL);
@ -3383,28 +3387,10 @@ static qboolean GLBE_RegisterLightShader(int mode)
qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode)
{
extern cvar_t gl_specular;
#ifdef RTLIGHTS
float view[16];
extern cvar_t r_shadow_shadowmapping, r_shadow_shadowmapping_nearclip;
/*generate light projection information*/
if (lmode == LSHADER_SPOT)
{
float proj[16];
Matrix4x4_CM_Projection_Far(proj, dl->fov, dl->fov, r_shadow_shadowmapping_nearclip.value, dl->radius);
Matrix4x4_CM_ModelViewMatrixFromAxis(view, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin);
Matrix4_Multiply(proj, view, shaderstate.lightprojmatrix);
}
if (lmode == LSHADER_SMAP)
{
// Matrix4x4_CM_Projection_Far(proj, 90, 90, nearplane, dl->radius);
Matrix4x4_CM_ModelViewMatrixFromAxis(shaderstate.lightprojmatrix, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin);
}
#endif
shaderstate.lastuniform = 0;
shaderstate.curdlight = dl;
shaderstate.lightmode = 1u<<lmode;
shaderstate.lightmode = lmode;
/*simple info*/
shaderstate.lightradius = dl->radius;
@ -3413,15 +3399,39 @@ qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode)
VectorCopy(colour, shaderstate.lightcolours);
#ifdef RTLIGHTS
VectorCopy(dl->lightcolourscales, shaderstate.lightcolourscale);
shaderstate.lightcubemap = dl->cubetexture;
if (lmode & LSHADER_SPOT)
shaderstate.lightcubemap = r_nulltex;
else
shaderstate.lightcubemap = dl->cubetexture;
if (lmode != LSHADER_SPOT)
{
if (TEXVALID(shaderstate.lightcubemap) && GLBE_RegisterLightShader(shaderstate.lightmode | (1u<<LSHADER_CUBE)))
shaderstate.lightmode |= 1u<<LSHADER_CUBE;
}
if (TEXVALID(shaderstate.lightcubemap) && GLBE_RegisterLightShader(shaderstate.lightmode | LSHADER_CUBE))
shaderstate.lightmode |= LSHADER_CUBE;
if (!GLBE_RegisterLightShader(shaderstate.lightmode))
return false;
/*generate light projection information*/
if (shaderstate.lightmode & LSHADER_SPOT)
{
float view[16];
float proj[16];
extern cvar_t r_shadow_shadowmapping_nearclip;
Matrix4x4_CM_Projection_Far(proj, dl->fov, dl->fov, r_shadow_shadowmapping_nearclip.value, dl->radius);
Matrix4x4_CM_ModelViewMatrixFromAxis(view, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin);
Matrix4_Multiply(proj, view, shaderstate.lightprojmatrix);
}
else if (shaderstate.lightmode & (LSHADER_SMAP|LSHADER_CUBE))
{
Matrix4x4_CM_LightMatrixFromAxis(shaderstate.lightprojmatrix, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin);
/*
vec3_t down;
vec3_t back;
vec3_t right;
VectorScale(dl->axis[2], -1, down);
VectorScale(dl->axis[1], 1, right);
VectorScale(dl->axis[0], 1, back);
Matrix4x4_CM_ModelViewMatrixFromAxis(shaderstate.lightprojmatrix, down, back, right, dl->origin);
*/
}
#endif
return true;
@ -3514,6 +3524,10 @@ static void BE_LegacyLighting(void)
{
mesh = shaderstate.meshes[m];
//vbo-only mesh.
if (!mesh->xyz_array)
return;
col = coloursarray[0] + mesh->vbofirstvert*4;
ldir = texcoordarray[0] + mesh->vbofirstvert*3;
for (i = 0; i < mesh->numvertexes; i++, col+=4, ldir+=3)
@ -3613,6 +3627,7 @@ static void BE_LegacyLighting(void)
static void DrawMeshes(void)
{
const shader_t *altshader;
const shaderpass_t *p;
int passno;
int flags;
@ -3678,24 +3693,39 @@ static void DrawMeshes(void)
break;
#ifdef RTLIGHTS
case BEM_LIGHT:
if (!shaderstate.shader_light[shaderstate.lightmode])
BE_LegacyLighting();
altshader = shaderstate.curshader->bemoverrides[shaderstate.lightmode];
if (!altshader)
altshader = shaderstate.shader_light[shaderstate.lightmode];
if (altshader && altshader->prog)
BE_RenderMeshProgram(altshader, altshader->passes);
else
BE_RenderMeshProgram(shaderstate.shader_light[shaderstate.lightmode], shaderstate.shader_light[shaderstate.lightmode]->passes);
BE_LegacyLighting();
break;
case BEM_DEPTHNORM:
BE_RenderMeshProgram(shaderstate.depthnormshader, shaderstate.depthnormshader->passes);
altshader = shaderstate.curshader->bemoverrides[bemoverride_prelight];
if (!altshader)
altshader = shaderstate.depthnormshader;
if (altshader && altshader->prog)
BE_RenderMeshProgram(altshader, altshader->passes);
break;
#endif
case BEM_CREPUSCULAR:
if (shaderstate.curshader->flags & SHADER_SKY)
BE_RenderMeshProgram(shaderstate.crepskyshader, shaderstate.crepskyshader->passes);
else
BE_RenderMeshProgram(shaderstate.crepopaqueshader, shaderstate.crepopaqueshader->passes);
altshader = shaderstate.curshader->bemoverrides[bemoverride_crepuscular];
if (!altshader && (shaderstate.curshader->flags & SHADER_SKY))
altshader = shaderstate.crepskyshader;
if (!altshader)
altshader = shaderstate.crepopaqueshader;
if (altshader && altshader->prog)
BE_RenderMeshProgram(altshader, altshader->passes);
break;
case BEM_DEPTHONLY:
if (shaderstate.depthonlyshader)
BE_RenderMeshProgram(shaderstate.depthonlyshader, shaderstate.depthonlyshader->passes);
altshader = shaderstate.curshader->bemoverrides[bemoverride_depthonly];
if (!altshader)
altshader = shaderstate.depthonlyshader;
if (altshader && altshader->prog)
BE_RenderMeshProgram(altshader, altshader->passes);
else
{
GL_DeSelectProgram();
@ -4165,7 +4195,6 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
}
GL_ForceDepthWritable();
GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_reflection, r_nulltex, true);
qglViewport (0, 0, vid.pixelwidth/2, vid.pixelheight/2);
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.width/2;
@ -4174,14 +4203,15 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
r_refdef.pxrect.width = vid.pixelwidth/2;
r_refdef.pxrect.height = vid.pixelheight/2;
r_refdef.pxrect.y = r_refdef.pxrect.height;
qglViewport (r_refdef.pxrect.x, r_refdef.pxrect.height-r_refdef.pxrect.y, r_refdef.pxrect.width, r_refdef.pxrect.height);
GL_ForceDepthWritable();
qglClearColor(0, 0, 0, 0);
qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLR_DrawPortal(batch, cl.worldmodel->batches, 1);
GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false);
qglViewport (oprect.x, oprect.y - oprect.height, oprect.width, oprect.height);
r_refdef.vrect = orect;
r_refdef.pxrect = oprect;
qglViewport (r_refdef.pxrect.x, r_refdef.pxrect.height-r_refdef.pxrect.y, r_refdef.pxrect.width, r_refdef.pxrect.height);
}
if (batch->shader->flags & (SHADER_HASREFRACT|SHADER_HASREFRACTDEPTH))
{
@ -4217,7 +4247,6 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
else
GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_refraction, r_nulltex, true);
qglViewport (0, 0, vid.pixelwidth/2, vid.pixelheight/2);
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.width/2;
@ -4226,6 +4255,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
r_refdef.pxrect.width = vid.pixelwidth/2;
r_refdef.pxrect.height = vid.pixelheight/2;
r_refdef.pxrect.y = r_refdef.pxrect.height;
qglViewport (r_refdef.pxrect.x, r_refdef.pxrect.height-r_refdef.pxrect.y, r_refdef.pxrect.width, r_refdef.pxrect.height);
GL_ForceDepthWritable();
qglClearColor(0, 0, 0, 0);
@ -4233,9 +4263,9 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
GLR_DrawPortal(batch, cl.worldmodel->batches, ((batch->shader->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme
GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false);
qglViewport (oprect.x, oprect.y - oprect.height, oprect.width, oprect.height);
r_refdef.vrect = ovrect;
r_refdef.pxrect = oprect;
qglViewport (r_refdef.pxrect.x, r_refdef.pxrect.height-r_refdef.pxrect.y, r_refdef.pxrect.width, r_refdef.pxrect.height);
}
else
GLR_DrawPortal(batch, cl.worldmodel->batches, 3);
@ -4245,6 +4275,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
vrect_t orect = r_refdef.vrect, oprect = r_refdef.pxrect;
if (!shaderstate.tex_ripplemap.num)
{
//FIXME: can we use RGB8 instead?
shaderstate.tex_ripplemap = GL_AllocNewTexture("***tex_ripplemap***", vid.pixelwidth/2, vid.pixelheight/2, 0);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@ -4254,7 +4285,6 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_ripplemap, r_nulltex, false);
qglViewport (0, 0, vid.pixelwidth/2, vid.pixelheight/2);
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.width/2;
@ -4263,6 +4293,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
r_refdef.pxrect.width = vid.pixelwidth/2;
r_refdef.pxrect.height = vid.pixelheight/2;
r_refdef.pxrect.y = r_refdef.pxrect.height;
qglViewport (r_refdef.pxrect.x, r_refdef.pxrect.height-r_refdef.pxrect.y, r_refdef.pxrect.width, r_refdef.pxrect.height);
qglClearColor(0, 0, 0, 0);
qglClear(GL_COLOR_BUFFER_BIT);
@ -4274,9 +4305,9 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
r_refdef.recurse = false;
GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false);
qglViewport (oprect.x, oprect.height + oprect.y, oprect.width, oprect.height);
r_refdef.vrect = orect;
r_refdef.pxrect = oprect;
qglViewport (r_refdef.pxrect.x, r_refdef.pxrect.height-r_refdef.pxrect.y, r_refdef.pxrect.width, r_refdef.pxrect.height);
}
BE_SelectMode(oldbem);
}
@ -4388,7 +4419,10 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco
shaderstate.tex_sourcecol = sourcecol;
shaderstate.tex_sourcedepth = sourcedepth;
if (!destcol.num)
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
{
shaderstate.fbo_current = 0;
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_current);
}
else
{
if (usedepth)
@ -4422,6 +4456,7 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco
}
else
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_diffuse);
shaderstate.fbo_current = shaderstate.fbo_diffuse;
if (destdepth.num)
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, destdepth.num, 0);
@ -4440,6 +4475,8 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco
}
else
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_depthless);
shaderstate.fbo_current = shaderstate.fbo_depthless;
}
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, destcol.num, 0);
@ -4585,6 +4622,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
if (!r_refdef.recurse)
{
shaderstate.fbo_current = 0; //just in case something crashed
GL_DoSwap();
if (shaderstate.wbatch + 50 > shaderstate.maxwbatches)
{

File diff suppressed because it is too large Load Diff

View File

@ -72,7 +72,7 @@ void GL_Draw_HL_AliasFrame(short *order, vec3_t *transformed, float tex_w, float
=======================================================================================================================
*/
extern char loadname[];
qboolean Mod_LoadHLModel (model_t *mod, void *buffer)
qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer)
{
/*~~*/
int i;

View File

@ -39,14 +39,11 @@ char loadname[32]; // for hunk tags
void CM_Init(void);
qboolean Mod_LoadSpriteModel (model_t *mod, void *buffer);
qboolean Mod_LoadSprite2Model (model_t *mod, void *buffer);
qboolean Mod_LoadBrushModel (model_t *mod, void *buffer);
qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer);
qboolean QDECL Mod_LoadSprite2Model (model_t *mod, void *buffer);
qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer);
#ifdef Q2BSPS
qboolean Mod_LoadQ2BrushModel (model_t *mod, void *buffer);
#endif
#ifdef HALFLIFEMODELS
qboolean Mod_LoadHLModel (model_t *mod, void *buffer);
qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer);
#endif
model_t *Mod_LoadModel (model_t *mod, qboolean crash);
@ -58,7 +55,7 @@ qboolean Mod_LoadDoomLevel(model_t *mod);
void Mod_LoadDoomSprite (model_t *mod);
#endif
#define MAX_MOD_KNOWN 2048
#define MAX_MOD_KNOWN 8192
model_t mod_known[MAX_MOD_KNOWN];
int mod_numknown;
@ -438,33 +435,51 @@ void Mod_ClearAll (void)
mod_datasequence++;
}
//called after all new content has been precached
void Mod_Flush(qboolean force)
//can be called in one of two ways.
//force=true: explicit flush. everything goes, even if its still in use.
//force=false: map change. lots of stuff is no longer in use and can be freely flushed.
//certain models cannot be safely flushed while still in use. such models will not be flushed even if forced (they may still be partially flushed).
void Mod_Purge(enum mod_purge_e ptype)
{
int i;
model_t *mod;
qboolean unused;
for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
{
if (mod->needload)
continue;
unused = mod->datasequence != mod_datasequence;
//this model isn't active any more.
if (mod->datasequence != mod_datasequence || force)
if (unused || ptype != MP_MAPCHANGED)
{
Con_DPrintf("model \"%s\" no longer needed\n", mod->name);
if (unused)
Con_DPrintf("model \"%s\" no longer needed\n", mod->name);
#ifdef TERRAIN
//we can safely flush all terrain sections at any time
if (mod->terrain && ptype != MP_MAPCHANGED)
Terr_PurgeTerrainModel(mod, false, true);
#endif
//purge any vbos
if (mod->type == mod_brush)
{
//brush models cannot be safely flushed.
if (!unused && ptype != MP_RESET)
continue;
Surf_Clear(mod);
}
#ifdef TERRAIN
//nuke terrain buffers
if (mod->terrain)
if (mod->type == mod_brush || mod->type == mod_heightmap)
{
Terr_PurgeTerrainModel(mod, false, false);
mod->terrain = NULL;
//heightmap/terrain models cannot be safely flushed (brush models might have terrain embedded).
if (!unused && ptype != MP_RESET)
continue;
Terr_FreeModel(mod);
}
#endif
@ -481,28 +496,71 @@ void Mod_Flush(qboolean force)
Mod_Init
===============
*/
void Mod_Init (void)
void Mod_Init (qboolean initial)
{
Mod_ClearAll(); //shouldn't be needed
Mod_Flush(true);//shouldn't be needed
mod_numknown = 0;
Q1BSP_Init();
if (!initial)
{
Mod_ClearAll(); //shouldn't be needed
Mod_Purge(MP_RESET);//shouldn't be needed
mod_numknown = 0;
Q1BSP_Init();
Cmd_AddCommand("mod_memlist", Mod_MemList_f);
Cmd_AddCommand("mod_batchlist", Mod_BatchList_f);
Cmd_AddCommand("mod_texturelist", Mod_TextureList_f);
Cmd_AddCommand("mod_usetexture", Mod_BlockTextureColour_f);
Cmd_AddCommand("mod_memlist", Mod_MemList_f);
Cmd_AddCommand("mod_batchlist", Mod_BatchList_f);
Cmd_AddCommand("mod_texturelist", Mod_TextureList_f);
Cmd_AddCommand("mod_usetexture", Mod_BlockTextureColour_f);
}
if (initial)
{
Alias_Register();
Mod_RegisterModelFormatMagic(NULL, "Quake1 Sprite (spr)", IDSPRITEHEADER, Mod_LoadSpriteModel);
#ifdef SP2MODELS
Mod_RegisterModelFormatMagic(NULL, "Quake2 Sprite (sp2)", IDSPRITE2HEADER, Mod_LoadSprite2Model);
#endif
//q2/q3bsps
#ifdef Q2BSPS
Mod_RegisterModelFormatMagic(NULL, "Quake2/Quake2 Map (bsp)", IDBSPHEADER, Mod_LoadQ2BrushModel);
#endif
#ifdef Q3BSPS
Mod_RegisterModelFormatMagic(NULL, "Raven Map (bsp)", ('R'<<0)+('B'<<8)+('S'<<16)+('P'<<24), Mod_LoadQ2BrushModel);
Mod_RegisterModelFormatMagic(NULL, "QFusion Map (bsp)", ('F'<<0)+('B'<<8)+('S'<<16)+('P'<<24), Mod_LoadQ2BrushModel);
#endif
//doom maps
#ifdef MAP_DOOM
Mod_RegisterModelFormatMagic(NULL, "Doom IWad Map", (('D'<<24)+('A'<<16)+('W'<<8)+'I'), Mod_LoadDoomLevel);
Mod_RegisterModelFormatMagic(NULL, "Doom PWad Map", (('D'<<24)+('A'<<16)+('W'<<8)+'P'), Mod_LoadDoomLevel);
#endif
//q1-based formats
Mod_RegisterModelFormatMagic(NULL, "Quake1 2PSB Map(bsp)", BSPVERSION_LONG1, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 BSP2 Map(bsp)", BSPVERSION_LONG2, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Half-Life Map (bsp)", 30, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 Map (bsp)", 29, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 Prerelease Map (bsp)", 28, Mod_LoadBrushModel);
}
}
void Mod_Shutdown (void)
void Mod_Shutdown (qboolean final)
{
Mod_ClearAll();
Mod_Flush(true);
mod_numknown = 0;
if (final)
{
Mod_UnRegisterAllModelFormats(NULL);
}
else
{
Mod_ClearAll();
Mod_Purge(MP_RESET);
mod_numknown = 0;
Cmd_RemoveCommand("mod_batchlist");
Cmd_RemoveCommand("mod_texturelist");
Cmd_RemoveCommand("mod_usetexture");
Cmd_RemoveCommand("mod_memlist");
Cmd_RemoveCommand("mod_batchlist");
Cmd_RemoveCommand("mod_texturelist");
Cmd_RemoveCommand("mod_usetexture");
}
}
/*
@ -604,6 +662,9 @@ model_t *Mod_FindName (char *name)
mod->particletrail = -1;
}
if (mod->needload == 2)
mod->needload = true;
//mark it as active, so it doesn't get flushed prematurely
mod->datasequence = mod_datasequence;
return mod;
@ -630,6 +691,93 @@ void Mod_TouchModel (char *name)
}
}
static struct
{
void *module;
char *formatname;
char *ident;
unsigned int magic;
qboolean (QDECL *load) (model_t *mod, void *buffer);
} modelloaders[64];
int Mod_RegisterModelFormatText(void *module, const char *formatname, char *magictext, qboolean (QDECL *load) (model_t *mod, void *buffer))
{
int i, free = -1;
for (i = 0; i < sizeof(modelloaders)/sizeof(modelloaders[0]); i++)
{
if (modelloaders[i].ident && !strcmp(modelloaders[i].ident, magictext))
{
free = i;
break; //extension match always replaces
}
else if (!modelloaders[i].load && free < 0)
free = i;
}
if (free < 0)
return 0;
modelloaders[free].module = module;
modelloaders[free].formatname = Z_StrDup(formatname);
modelloaders[free].magic = 0;
modelloaders[free].ident = Z_StrDup(magictext);
modelloaders[free].load = load;
return free+1;
}
int Mod_RegisterModelFormatMagic(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (model_t *mod, void *buffer))
{
int i, free = -1;
for (i = 0; i < sizeof(modelloaders)/sizeof(modelloaders[0]); i++)
{
if (modelloaders[i].magic && modelloaders[i].magic == magic)
{
free = i;
break; //extension match always replaces
}
else if (!modelloaders[i].load && free < 0)
free = i;
}
if (free < 0)
return 0;
modelloaders[free].module = module;
if (modelloaders[free].formatname)
Z_Free(modelloaders[free].formatname);
modelloaders[free].formatname = Z_StrDup(formatname);
modelloaders[free].magic = magic;
modelloaders[free].ident = NULL;
modelloaders[free].load = load;
return free+1;
}
void Mod_UnRegisterModelFormat(int idx)
{
idx--;
if ((unsigned int)(idx) >= sizeof(modelloaders)/sizeof(modelloaders[0]))
return;
Z_Free(modelloaders[idx].ident);
modelloaders[idx].ident = NULL;
Z_Free(modelloaders[idx].formatname);
modelloaders[idx].formatname = NULL;
modelloaders[idx].magic = 0;
modelloaders[idx].load = NULL;
modelloaders[idx].module = NULL;
//FS_Restart will be needed
}
void Mod_UnRegisterAllModelFormats(void *module)
{
int i;
for (i = 0; i < sizeof(modelloaders)/sizeof(modelloaders[0]); i++)
{
if (modelloaders[i].module == module)
Mod_UnRegisterModelFormat(i+1);
}
}
/*
==================
Mod_LoadModel
@ -644,6 +792,7 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash)
char mdlbase[MAX_QPATH];
char *replstr;
qboolean doomsprite = false;
unsigned int magic, i;
char *ext;
@ -685,6 +834,9 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash)
}
#endif
if (mod->needload == 2)
return mod;
//
// load the file
//
@ -783,141 +935,40 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash)
//
Mod_DoCRC(mod, (char*)buf, com_filesize);
switch (LittleLong(*(unsigned *)buf))
magic = LittleLong(*(unsigned *)buf);
for(i = 0; i < sizeof(modelloaders) / sizeof(modelloaders[0]); i++)
{
//The binary 3d mesh model formats
case RAPOLYHEADER:
case IDPOLYHEADER:
TRACE(("Mod_LoadModel: Q1 mdl\n"));
if (!Mod_LoadQ1Model(mod, buf))
if (modelloaders[i].load && modelloaders[i].magic == magic && !modelloaders[i].ident)
break;
}
if (i < sizeof(modelloaders) / sizeof(modelloaders[0]))
{
if (!modelloaders[i].load(mod, buf))
continue;
break;
#ifdef MD2MODELS
case MD2IDALIASHEADER:
TRACE(("Mod_LoadModel: md2\n"));
if (!Mod_LoadQ2Model(mod, buf))
continue;
break;
#endif
#ifdef MD3MODELS
case MD3_IDENT:
TRACE(("Mod_LoadModel: md3\n"));
if (!Mod_LoadQ3Model (mod, buf))
continue;
Surf_BuildModelLightmaps(mod);
break;
#endif
#ifdef HALFLIFEMODELS
case (('T'<<24)+('S'<<16)+('D'<<8)+'I'):
TRACE(("Mod_LoadModel: HL mdl\n"));
if (!Mod_LoadHLModel (mod, buf))
continue;
break;
#endif
//Binary skeletal model formats
#ifdef ZYMOTICMODELS
case (('O'<<24)+('M'<<16)+('Y'<<8)+'Z'):
TRACE(("Mod_LoadModel: zym\n"));
if (!Mod_LoadZymoticModel(mod, buf))
continue;
break;
#endif
#ifdef DPMMODELS
case (('K'<<24)+('R'<<16)+('A'<<8)+'D'):
TRACE(("Mod_LoadModel: dpm\n"));
if (!Mod_LoadDarkPlacesModel(mod, buf))
continue;
break;
#endif
#ifdef PSKMODELS
case ('A'<<0)+('C'<<8)+('T'<<16)+('R'<<24):
TRACE(("Mod_LoadModel: psk\n"));
if (!Mod_LoadPSKModel (mod, buf))
continue;
break;
#endif
#ifdef INTERQUAKEMODELS
case ('I'<<0)+('N'<<8)+('T'<<16)+('E'<<24):
TRACE(("Mod_LoadModel: IQM\n"));
if (!Mod_LoadInterQuakeModel (mod, buf))
continue;
break;
#endif
//Binary Sprites
#ifdef SP2MODELS
case IDSPRITE2HEADER:
TRACE(("Mod_LoadModel: q2 sp2\n"));
if (!Mod_LoadSprite2Model (mod, buf))
continue;
break;
#endif
case IDSPRITEHEADER:
TRACE(("Mod_LoadModel: q1 spr\n"));
if (!Mod_LoadSpriteModel (mod, buf))
continue;
break;
//Binary Map formats
#if defined(Q2BSPS) || defined(Q3BSPS)
case ('F'<<0)+('B'<<8)+('S'<<16)+('P'<<24):
case ('R'<<0)+('B'<<8)+('S'<<16)+('P'<<24):
case IDBSPHEADER: //looks like id switched to have proper ids
TRACE(("Mod_LoadModel: q2/q3/raven/fusion bsp\n"));
if (!Mod_LoadQ2BrushModel (mod, buf))
continue;
Surf_BuildModelLightmaps(mod);
break;
#endif
#ifdef MAP_DOOM
case (('D'<<24)+('A'<<16)+('W'<<8)+'I'): //the id is hacked by the FS .wad loader (main wad).
case (('D'<<24)+('A'<<16)+('W'<<8)+'P'): //the id is hacked by the FS .wad loader (patch wad).
TRACE(("Mod_LoadModel: doom iwad/pwad map\n"));
if (!Mod_LoadDoomLevel (mod))
continue;
break;
#endif
case BSPVERSION_LONG1:
Con_Printf("WARNING: %s is in a deprecated format\n", mod->name);
case 30: //hl
case 29: //q1
case 28: //prerel
case BSPVERSION_LONG2:
TRACE(("Mod_LoadModel: hl/q1 bsp\n"));
if (!Mod_LoadBrushModel (mod, buf))
continue;
Surf_BuildModelLightmaps(mod);
break;
//Text based misc types.
default:
//check for text based headers
if (mod->type == mod_brush)
Surf_BuildModelLightmaps(mod);
}
else
{
COM_Parse((char*)buf);
#ifdef MD5MODELS
if (!strcmp(com_token, "MD5Version")) //doom3 format, text based, skeletal
for(i = 0; i < sizeof(modelloaders) / sizeof(modelloaders[0]); i++)
{
TRACE(("Mod_LoadModel: md5mesh/md5anim\n"));
if (!Mod_LoadMD5MeshModel (mod, buf))
continue;
break;
if (modelloaders[i].load && modelloaders[i].ident && !strcmp(modelloaders[i].ident, com_token))
break;
}
if (!strcmp(com_token, "EXTERNALANIM")) //custom format, text based, specifies skeletal models to load and which md5anim files to use.
if (i < sizeof(modelloaders) / sizeof(modelloaders[0]))
{
TRACE(("Mod_LoadModel: blurgh\n"));
if (!Mod_LoadCompositeAnim (mod, buf))
if (!modelloaders[i].load(mod, buf))
continue;
break;
}
#endif
else
{
Con_Printf(CON_WARNING "Unrecognised model format 0x%x (%c%c%c%c)\n", LittleLong(*(unsigned *)buf), ((char*)buf)[0], ((char*)buf)[1], ((char*)buf)[2], ((char*)buf)[3]);
continue;
}
}
/*
#ifdef MAP_PROC
if (!strcmp(com_token, "CM")) //doom3 map.
{
@ -927,19 +978,7 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash)
break;
}
#endif
#ifdef TERRAIN
if (!strcmp(com_token, "terrain")) //custom format, text based.
{
TRACE(("Mod_LoadModel: terrain\n"));
if (!Terr_LoadTerrainModel(mod, buf))
continue;
break;
}
#endif
Con_Printf(CON_WARNING "Unrecognised model format 0x%x (%c%c%c%c)\n", LittleLong(*(unsigned *)buf), ((char*)buf)[0], ((char*)buf)[1], ((char*)buf)[2], ((char*)buf)[3]);
continue;
}
*/
P_LoadedModel(mod);
Validation_IncludeFile(mod->name, (char *)buf, com_filesize);
@ -974,7 +1013,7 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash)
mod->maxs[0] = 16;
mod->maxs[1] = 16;
mod->maxs[2] = 16;
mod->needload = true;
mod->needload = 2;
mod->engineflags = 0;
P_LoadedModel(mod);
return mod;
@ -4007,7 +4046,7 @@ void Mod_FixupMinsMaxs(void)
Mod_LoadBrushModel
=================
*/
qboolean Mod_LoadBrushModel (model_t *mod, void *buffer)
qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer)
{
int i, j;
dheader_t *header;
@ -4275,7 +4314,7 @@ TRACE(("LoadBrushModel %i\n", __LINE__));
TRACE(("LoadBrushModel %i\n", __LINE__));
#ifdef TERRAIN
lm->terrain = Mod_LoadTerrainInfo(lm, loadname);
lm->terrain = Mod_LoadTerrainInfo(lm, loadname, false);
#endif
return true;
}
@ -4445,7 +4484,7 @@ static void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int fra
Mod_LoadSpriteModel
=================
*/
qboolean Mod_LoadSpriteModel (model_t *mod, void *buffer)
qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer)
{
int i;
int version;
@ -4569,7 +4608,7 @@ qboolean Mod_LoadSpriteModel (model_t *mod, void *buffer)
}
#ifdef SP2MODELS
qboolean Mod_LoadSprite2Model (model_t *mod, void *buffer)
qboolean QDECL Mod_LoadSprite2Model (model_t *mod, void *buffer)
{
int i;
int version;

View File

@ -232,18 +232,6 @@ typedef struct
#define SIDE_BACK 1
#define SIDE_ON 2
// plane_t structure
// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct mplane_s
{
vec3_t normal;
float dist;
qbyte type; // for texture axis selection and fast side tests
qbyte signbits; // signx + signy<<1 + signz<<1
qbyte pad[2];
} mplane_t;
typedef struct vbo_s
{
unsigned int numvisible;
@ -992,9 +980,9 @@ qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model);
#ifdef TERRAIN
void Terr_Init(void);
void Terr_DrawTerrainModel (batch_t **batch, entity_t *e);
qboolean Terr_LoadTerrainModel (model_t *mod, void *buffer);
void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly, qboolean lightmapreusable);
void *Mod_LoadTerrainInfo(model_t *mod, char *loadname); //call this after loading a bsp
void Terr_FreeModel(model_t *mod);
void Terr_PurgeTerrainModel(model_t *hm, qboolean lightmapsonly, qboolean lightmapreusable);
void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force); //call this after loading a bsp
qboolean Terrain_LocateSection(char *name, flocation_t *loc); //used on servers to generate sections for download.
qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentmask, struct trace_s *trace);
unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org);

View File

@ -194,13 +194,14 @@ void R_InitFlashblends(void)
"blendfunc gl_one gl_one\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"nodepth\n"
"}\n"
"}\n"
);
lpplight_shader = NULL;
}
static qboolean R_BuildDlightMesh(dlight_t *light, float colscale, float radscale, qboolean expand)
static qboolean R_BuildDlightMesh(dlight_t *light, float colscale, float radscale, int dtype)
{
int i, j;
// float a;
@ -231,7 +232,7 @@ static qboolean R_BuildDlightMesh(dlight_t *light, float colscale, float radscal
}
VectorSubtract (light->origin, r_origin, v);
if (Length (v) < rad + gl_mindist.value*2)
if (dtype != 1 && Length (v) < rad + gl_mindist.value*2)
{ // view is inside the dlight
return false;
}
@ -250,10 +251,14 @@ static qboolean R_BuildDlightMesh(dlight_t *light, float colscale, float radscal
bub_sin++;
bub_cos++;
}
if (!expand)
VectorMA(flashblend_vcoords[0], -rad/1.5, vpn, flashblend_vcoords[0]);
else
if (dtype == 0)
{
//flashblend 3d-ish
VectorMA(flashblend_vcoords[0], -rad/1.5, vpn, flashblend_vcoords[0]);
}
else if (dtype != 1)
{
//prepass lights needs to be fully infront of the light. the glsl is a fullscreen-style effect, but we can benefit from early-z and scissoring
vec3_t diff;
VectorSubtract(r_origin, light->origin, diff);
VectorNormalize(diff);
@ -274,10 +279,11 @@ void R_RenderDlights (void)
dlight_t *l;
vec3_t waste1, waste2;
unsigned int beflags = 0;
float intensity;
float intensity, cscale;
qboolean coronastyle;
if (r_coronas.value)
beflags |= BEF_FORCENODEPTH;
if (!r_coronas.value && !r_flashblend.value)
return;
// r_dlightframecount = r_framecount + 1; // because the count hasn't
// advanced yet for this frame
@ -293,32 +299,38 @@ void R_RenderDlights (void)
if (l->flags & LFLAG_FLASHBLEND)
{
if (!r_flashblend.value)
continue;
//dlights emitting from the local player are not visible as flashblends
if (l->key == r_refdef.playerview->viewentity)
continue; //was a glow
if (l->key == -(r_refdef.playerview->viewentity))
continue; //was a muzzleflash
coronastyle = false;
}
intensity = l->corona * 0.25;
if (r_flashblend.value && (l->flags & LFLAG_FLASHBLEND))
intensity = l->corona; /*intensity is already in the corona value...*/
else
intensity = l->corona * r_coronas.value;
if (intensity <= 0)
coronastyle = true;
cscale = l->coronascale;
intensity = l->corona * 0.25;
if (coronastyle)
intensity *= r_coronas.value;
else
intensity *= r_flashblend.value;
if (intensity <= 0 || cscale <= 0)
continue;
/*coronas use depth testing to compute visibility*/
if (r_coronas.value)
if (coronastyle)
{
if (TraceLineN(r_refdef.vieworg, l->origin, waste1, waste2))
continue;
}
if (!R_BuildDlightMesh (l, intensity, l->coronascale, false) && r_flashblend.value)
if (!R_BuildDlightMesh (l, intensity, cscale, coronastyle) && !coronastyle)
AddLightBlend (l->color[0], l->color[1], l->color[2], l->radius * 0.0003);
else
BE_DrawMesh_Single(flashblend_shader, &flashblend_mesh, NULL, &flashblend_shader->defaulttextures, beflags);
BE_DrawMesh_Single(flashblend_shader, &flashblend_mesh, NULL, &flashblend_shader->defaulttextures, (coronastyle?BEF_FORCENODEPTH|BEF_FORCEADDITIVE:0)|beflags);
}
}
@ -328,9 +340,9 @@ void R_GenDlightMesh(struct batch_s *batch)
static mesh_t *meshptr;
dlight_t *l = cl_dlights + batch->surf_first;
BE_SelectDLight(l, l->color, LSHADER_STANDARD);
BE_SelectDLight(l, l->color, 0);
if (!R_BuildDlightMesh (l, 2, 1, true))
if (!R_BuildDlightMesh (l, 2, 1, 2))
{
int i;
static vec2_t s[4] = {{1, -1}, {-1, -1}, {-1, 1}, {1, 1}};
@ -693,6 +705,7 @@ void R_ImportRTLights(char *entlump)
break;
VectorCopy(origin, dl->origin);
AngleVectors(angles, dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
dl->radius = radius;
VectorCopy(color, dl->color);
dl->flags = 0;
@ -827,6 +840,7 @@ void R_LoadRTLights(void)
dl->lightcolourscales[1] = diffusescale;
dl->lightcolourscales[2] = specularscale;
AngleVectors(angles, dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
Q_strncpyz(dl->cubemapname, cubename, sizeof(dl->cubemapname));
if (*dl->cubemapname)

View File

@ -950,12 +950,17 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype)
// qglClipPlane(GL_CLIP_PLANE0, glplane);
// qglEnable(GL_CLIP_PLANE0);
// }
frustum[4].normal[0] = plane.normal[0];
frustum[4].normal[1] = plane.normal[1];
frustum[4].normal[2] = plane.normal[2];
frustum[4].dist = plane.dist + 0.01;
if (portaltype == 1 || portaltype == 2)
R_ObliqueNearClip(&frustum[4]);
if (r_refdef.frustum_numplanes < MAXFRUSTUMPLANES)
{
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] = plane.normal[0];
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] = plane.normal[1];
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] = plane.normal[2];
r_refdef.frustum[r_refdef.frustum_numplanes].dist = plane.dist + 0.01;
if (portaltype == 1 || portaltype == 2)
R_ObliqueNearClip(&r_refdef.frustum[r_refdef.frustum_numplanes]);
r_refdef.frustum_numplanes++;
}
R_RenderScene();
// if (qglClipPlane)
// qglDisable(GL_CLIP_PLANE0);
@ -970,7 +975,6 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype)
/*broken stuff*/
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
VectorCopy (r_refdef.vieworg, r_origin);
R_SetFrustum (r_refdef.m_projection, r_refdef.m_view);
if (qglLoadMatrixf)
{
@ -1394,6 +1398,9 @@ void GLR_RenderView (void)
if ((r_refdef.flags & Q2RDF_NOWORLDMODEL) || r_secondaryview)
return;
if (r_secondaryview)
return;
if (r_bloom.value)
R_BloomBlend();

View File

@ -218,7 +218,9 @@ static enum {
SPM_DOOM3,
} shaderparsemode;
shader_t *r_shaders;
unsigned int r_numshaders;
unsigned int r_maxshaders;
shader_t **r_shaders;
static hashtable_t shader_active_hash;
void *shader_active_hash_mem;
@ -1866,21 +1868,10 @@ static void Shader_ProgAutoFields(program_t *prog, char **cvarnames, int *cvarty
#endif
}
static void Shader_SLProgramName (shader_t *shader, shaderpass_t *pass, char **ptr, int qrtype)
static char *Shader_ParseBody(char *debugname, char **ptr)
{
/*accepts:
program
{
BLAH
}
where BLAH is both vertex+frag with #ifdefs
or
program fname
on one line.
*/
char *programbody;
char *body;
char *start, *end;
char *hash;
end = *ptr;
while (*end == ' ' || *end == '\t' || *end == '\r')
@ -1893,7 +1884,7 @@ static void Shader_SLProgramName (shader_t *shader, shaderpass_t *pass, char **p
end++;
if (*end != '{')
{
Con_Printf("shader \"%s\" missing program string\n", shader->name);
Con_Printf("shader \"%s\" missing program string\n", debugname);
}
else
{
@ -1910,22 +1901,45 @@ static void Shader_SLProgramName (shader_t *shader, shaderpass_t *pass, char **p
else if (*end == '{')
count++;
}
programbody = BZ_Malloc(end - start + 1);
memcpy(programbody, start, end-start);
programbody[end-start] = 0;
body = BZ_Malloc(end - start + 1);
memcpy(body, start, end-start);
body[end-start] = 0;
*ptr = end+1;/*skip over it all*/
shader->prog = malloc(sizeof(*shader->prog));
memset(shader->prog, 0, sizeof(*shader->prog));
shader->prog->refs = 1;
if (!Shader_LoadPermutations(shader->name, shader->prog, programbody, qrtype, 0))
{
free(shader->prog);
shader->prog = NULL;
}
BZ_Free(programbody);
return body;
}
}
return NULL;
}
static void Shader_SLProgramName (shader_t *shader, shaderpass_t *pass, char **ptr, int qrtype)
{
/*accepts:
program
{
BLAH
}
where BLAH is both vertex+frag with #ifdefs
or
program fname
on one line.
*/
char *programbody;
char *hash;
programbody = Shader_ParseBody(shader->name, ptr);
if (programbody)
{
shader->prog = malloc(sizeof(*shader->prog));
memset(shader->prog, 0, sizeof(*shader->prog));
shader->prog->refs = 1;
if (!Shader_LoadPermutations(shader->name, shader->prog, programbody, qrtype, 0))
{
free(shader->prog);
shader->prog = NULL;
}
BZ_Free(programbody);
return;
}
@ -2129,6 +2143,87 @@ static void Shader_DP_Camera(shader_t *shader, shaderpass_t *pass, char **ptr)
shader->sort = SHADER_SORT_PORTAL;
}
static void Shader_BEMode(shader_t *shader, shaderpass_t *pass, char **ptr)
{
int mode;
char tokencopy[1024];
char *token;
char *embed = NULL;
token = Shader_ParseString(ptr);
if (!Q_stricmp(token, "rtlight"))
mode = -1; //all light types
else if (!Q_stricmp(token, "rtlight_only"))
mode = LSHADER_STANDARD;
else if (!Q_stricmp(token, "rtlight_smap"))
mode = LSHADER_SMAP;
else if (!Q_stricmp(token, "rtlight_spot"))
mode = LSHADER_SPOT;
else if (!Q_stricmp(token, "rtlight_cube"))
mode = LSHADER_CUBE;
else if (!Q_stricmp(token, "rtlight_cube_smap"))
mode = LSHADER_CUBE|LSHADER_SMAP;
else if (!Q_stricmp(token, "rtlight_cube_spot")) //doesn't make sense.
mode = LSHADER_CUBE|LSHADER_SPOT;
else if (!Q_stricmp(token, "rtlight_spot_smap"))
mode = LSHADER_SMAP|LSHADER_SPOT;
else if (!Q_stricmp(token, "rtlight_cube_spot_smap")) //doesn't make sense.
mode = LSHADER_CUBE|LSHADER_SPOT|LSHADER_SMAP;
else if (!Q_stricmp(token, "crepuscular"))
mode = bemoverride_crepuscular;
else if (!Q_stricmp(token, "depthonly"))
mode = bemoverride_depthonly;
else if (!Q_stricmp(token, "depthdark"))
mode = bemoverride_depthdark;
else if (!Q_stricmp(token, "prelight"))
mode = bemoverride_prelight;
else if (!Q_stricmp(token, "fog"))
mode = bemoverride_fog;
else
{
Con_DPrintf(CON_WARNING "Shader %s specifies unknown bemode %s.\n", shader->name, token);
return; //not supported.
}
embed = Shader_ParseBody(shader->name, ptr);
if (embed)
{
int l = strlen(embed) + 6;
char *b = BZ_Malloc(l);
Q_snprintfz(b, l, "{\n%s\n}\n", embed);
BZ_Free(embed);
embed = b;
//generate a unique name
Q_snprintfz(tokencopy, sizeof(tokencopy), "%s_mode%i", shader->name, mode);
}
else
{
token = Shader_ParseString(ptr);
Q_strncpyz(tokencopy, token, sizeof(tokencopy)); //make sure things don't go squiff.
}
if (mode == -1)
{
//shorthand for rtlights
for (mode = 0; mode < LSHADER_MODES; mode++)
{
if ((mode & LSHADER_CUBE) && (mode & LSHADER_SPOT))
continue;
shader->bemoverrides[mode] = R_RegisterCustom(va("%s%s%s%s",
tokencopy,
(mode & LSHADER_SMAP)?"#PCF":"",
(mode & LSHADER_SPOT)?"#SPOT":"",
(mode & LSHADER_CUBE)?"#CUBE":"")
, shader->usageflags, embed?Shader_DefaultScript:NULL, embed);
}
}
else
{
shader->bemoverrides[mode] = R_RegisterCustom(tokencopy, shader->usageflags, embed?Shader_DefaultScript:NULL, embed);
}
if (embed)
BZ_Free(embed);
}
static shaderkey_t shaderkeys[] =
{
{"cull", Shader_Cull},
@ -2141,13 +2236,16 @@ static shaderkey_t shaderkeys[] =
{"sort", Shader_Sort},
{"deformvertexes", Shader_DeformVertexes},
{"portal", Shader_Portal},
{"lpp_light", Shader_Prelight},
{"entitymergable", Shader_EntityMergable},
//fte extensions
{"lpp_light", Shader_Prelight},
{"glslprogram", Shader_GLSLProgramName},
{"program", Shader_ProgramName}, //legacy
{"program", Shader_ProgramName}, //gl or d3d
{"hlslprogram", Shader_HLSLProgramName}, //for d3d
{"param", Shader_ProgramParam},
{"param", Shader_ProgramParam}, //legacy
{"bemode", Shader_BEMode},
//dp compat
{"dp_camera", Shader_DP_Camera},
@ -3055,7 +3153,9 @@ qboolean Shader_Init (void)
if (!r_shaders)
{
r_shaders = calloc(MAX_SHADERS, sizeof(shader_t));
r_numshaders = 0;
r_maxshaders = 256;
r_shaders = calloc(r_maxshaders, sizeof(*r_shaders));
shader_hash = calloc (HASH_SIZE, sizeof(*shader_hash));
@ -3216,15 +3316,17 @@ void Shader_Shutdown (void)
shader_t *shader;
shadercache_t *cache, *cache_next;
shader = r_shaders;
if (!r_shaders)
return; /*nothing needs freeing yet*/
for (i = 0; i < MAX_SHADERS; i++, shader++)
for (i = 0; i < r_numshaders; i++)
{
if (!shader->uses)
shader = r_shaders[i];
if (!shader || !shader->uses)
continue;
Shader_Free(shader);
Z_Free(r_shaders[i]);
r_shaders[i] = NULL;
}
for (i = 0; i < HASH_SIZE; i++)
@ -3241,6 +3343,9 @@ void Shader_Shutdown (void)
Shader_FlushGenerics();
r_maxshaders = 0;
r_numshaders = 0;
free(r_shaders);
r_shaders = NULL;
free(shader_hash);
@ -4977,18 +5082,21 @@ void R_UnloadShader(shader_t *shader)
if (shader->uses-- == 1)
Shader_Free(shader);
}
static int R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defaultgen, const char *genargs)
static shader_t *R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defaultgen, const char *genargs)
{
int i, f = -1;
char shortname[MAX_QPATH];
char *hash;
shader_t *s;
if (!*name)
name = "gfx/white";
if (strchr(name, '#'))
hash = strchr(name, '#');
if (hash) //don't strip anything.
{
Q_strncpyz(shortname, name, sizeof(shortname));
hash = shortname+(hash-name);
}
else
{
@ -5007,17 +5115,16 @@ static int R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defa
//q3 has a separate (internal) shader for every lightmap.
if (!((s->usageflags ^ usageflags) & SUF_LIGHTMAP))
{
i = s - r_shaders;
r_shaders[i].uses++;
return i;
s->uses++;
return s;
}
s = Hash_GetNext(&shader_active_hash, shortname, s);
}
// not loaded, find a free slot
for (i = 0; i < MAX_SHADERS; i++)
for (i = 0; i < r_numshaders; i++)
{
if (!r_shaders[i].uses)
if (!r_shaders[i] || !r_shaders[i]->uses)
{
if ( f == -1 ) // free shader
{
@ -5027,13 +5134,32 @@ static int R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defa
}
}
if ( f == -1 )
if (f == -1)
{
Sys_Error( "R_LoadShader: Shader limit exceeded.");
return f;
shader_t **n;
int nm;
f = r_numshaders;
if (f == r_maxshaders)
{
nm = r_maxshaders * 2;
n = realloc(r_shaders, nm*sizeof(*n));
if (!n)
{
Sys_Error( "R_LoadShader: Shader limit exceeded.");
return NULL;
}
memset(n+r_maxshaders, 0, (nm - r_maxshaders)*sizeof(*n));
r_shaders = n;
r_maxshaders = nm;
}
}
s = &r_shaders[f];
s = r_shaders[f];
if (!s)
s = r_shaders[f] = Z_Malloc(sizeof(*s));
s->id = f;
if (r_numshaders < f+1)
r_numshaders = f+1;
Q_strncpyz(s->name, shortname, sizeof(s->name));
s->usageflags = usageflags;
@ -5043,6 +5169,10 @@ static int R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defa
else
s->genargs = NULL;
//now strip off the hash so we find the right shader script
if (hash)
*hash = 0;
if (ruleset_allow_shaders.ival)
{
#ifdef GLQUAKE
@ -5052,21 +5182,21 @@ static int R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defa
{
if (Shader_ParseShader(va("%s_gles2", shortname), shortname, s))
{
return f;
return s;
}
}
if (gl_config.glversion >= 3)
{
if (Shader_ParseShader(va("%s_glsl3", shortname), shortname, s))
{
return f;
return s;
}
}
if (gl_config.arb_shader_objects)
{
if (Shader_ParseShader(va("%s_glsl", shortname), shortname, s))
{
return f;
return s;
}
}
}
@ -5077,7 +5207,7 @@ static int R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defa
{
if (Shader_ParseShader(va("%s_hlsl", shortname), shortname, s))
{
return f;
return s;
}
}
}
@ -5088,14 +5218,14 @@ static int R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defa
{
if (Shader_ParseShader(va("%s_hlsl11", shortname), shortname, s))
{
return f;
return s;
}
}
}
#endif
if (Shader_ParseShader(shortname, shortname, s))
{
return f;
return s;
}
}
@ -5113,13 +5243,13 @@ static int R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defa
"}\n");
else
s->generator(shortname, s, s->genargs);
return f;
return s;
}
else
{
Shader_Free(s);
}
return -1;
return NULL;
}
void Shader_DoReload(void)
@ -5147,9 +5277,10 @@ void Shader_DoReload(void)
Font_InvalidateColour();
Shader_ReloadGenerics();
for (s = r_shaders, i = 0; i < MAX_SHADERS; i++, s++)
for (i = 0; i < r_numshaders; i++)
{
if (!s->uses)
s = r_shaders[i];
if (!s || !s->uses)
continue;
strcpy(shortname, s->name);
@ -5215,6 +5346,7 @@ cin_t *R_ShaderFindCinematic(char *name)
#else
int i;
char shortname[MAX_QPATH];
shader_t *s;
if (!r_shaders)
return NULL;
@ -5224,19 +5356,16 @@ cin_t *R_ShaderFindCinematic(char *name)
COM_CleanUpPath(shortname);
//try and find it
for (i = 0; i < MAX_SHADERS; i++)
for (i = 0; i < r_numshaders; i++)
{
if (!r_shaders[i].uses)
s = r_shaders[i];
if (!s || !s->uses)
continue;
if (!Q_stricmp (shortname, r_shaders[i].name) )
break;
if (!Q_stricmp (shortname, s->name) )
return R_ShaderGetCinematic(s);
}
if (i == MAX_SHADERS)
return NULL;
//found the named shader.
return R_ShaderGetCinematic(&r_shaders[i]);
return NULL;
#endif
}
@ -5248,7 +5377,7 @@ shader_t *R_RegisterPic (char *name)
image_width = 64;
image_height = 64;
shader = &r_shaders[R_LoadShader (name, SUF_2D, Shader_Default2D, NULL)];
shader = R_LoadShader (name, SUF_2D, Shader_Default2D, NULL);
/*worth a try*/
if (shader->width <= 0)
@ -5266,22 +5395,22 @@ shader_t *R_RegisterPic (char *name)
shader_t *R_RegisterShader (char *name, unsigned int usageflags, const char *shaderscript)
{
return &r_shaders[R_LoadShader (name, usageflags, Shader_DefaultScript, shaderscript)];
return R_LoadShader (name, usageflags, Shader_DefaultScript, shaderscript);
}
shader_t *R_RegisterShader_Lightmap (char *name)
{
return &r_shaders[R_LoadShader (name, SUF_LIGHTMAP, Shader_DefaultBSPLM, NULL)];
return R_LoadShader (name, SUF_LIGHTMAP, Shader_DefaultBSPLM, NULL);
}
shader_t *R_RegisterShader_Vertex (char *name)
{
return &r_shaders[R_LoadShader (name, 0, Shader_DefaultBSPVertex, NULL)];
return R_LoadShader (name, 0, Shader_DefaultBSPVertex, NULL);
}
shader_t *R_RegisterShader_Flare (char *name)
{
return &r_shaders[R_LoadShader (name, 0, Shader_DefaultBSPFlare, NULL)];
return R_LoadShader (name, 0, Shader_DefaultBSPFlare, NULL);
}
shader_t *R_RegisterSkin (char *shadername, char *modname)
@ -5296,7 +5425,7 @@ shader_t *R_RegisterSkin (char *shadername, char *modname)
memcpy(newsname, modname, b - modname);
memcpy(newsname + (b-modname), shadername, strlen(shadername)+1);
/*if the specified shader does not contain a path, try and load one relative to the name of the model*/
shader = &r_shaders[R_LoadShader (newsname, 0, Shader_DefaultSkin, NULL)];
shader = R_LoadShader (newsname, 0, Shader_DefaultSkin, NULL);
R_BuildDefaultTexnums(&shader->defaulttextures, shader);
@ -5305,15 +5434,11 @@ shader_t *R_RegisterSkin (char *shadername, char *modname)
return shader;
}
}
shader = &r_shaders[R_LoadShader (shadername, 0, Shader_DefaultSkin, NULL)];
shader = R_LoadShader (shadername, 0, Shader_DefaultSkin, NULL);
return shader;
}
shader_t *R_RegisterCustom (char *name, unsigned int usageflags, shader_gen_t *defaultgen, const void *args)
{
int i;
i = R_LoadShader (name, usageflags, defaultgen, args);
if (i < 0)
return NULL;
return &r_shaders[i];
return R_LoadShader (name, usageflags, defaultgen, args);
}
#endif //SERVERONLY

View File

@ -61,7 +61,7 @@ cvar_t r_editlights_import_radius = SCVAR ("r_editlights_import_radius", "1");
cvar_t r_editlights_import_ambient = SCVAR ("r_editlights_import_ambient", "0");
cvar_t r_editlights_import_diffuse = SCVAR ("r_editlights_import_diffuse", "1");
cvar_t r_editlights_import_specular = SCVAR ("r_editlights_import_specular", "1"); //excessive, but noticable. its called stylized, okay? shiesh, some people
cvar_t r_shadow_shadowmapping = SCVARF ("debug_r_shadow_shadowmapping", "0", 0);
cvar_t r_shadow_shadowmapping = SCVARF ("r_shadow_shadowmapping", "1", 0);
cvar_t r_shadow_shadowmapping_precision = CVARD ("r_shadow_shadowmapping_precision", "1", "Scales the shadowmap detail level up or down.");
extern cvar_t r_shadow_shadowmapping_nearclip;
extern cvar_t r_shadow_shadowmapping_bias;
@ -70,7 +70,7 @@ cvar_t r_sun_colour = CVARFD ("r_sun_colour", "0 0 0", CVAR_ARCHIVE, "Spec
static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour);
static qbyte lvisb[(MAX_MAP_LEAFS+7)>>3];
/*
called on framebuffer resize.
@ -975,7 +975,7 @@ static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis, unsigned char *v
cluster = leaf->cluster;
if (cluster == -1)
continue;
if (lvis[cluster>>3] & vvis[cluster>>3] & (1<<(cluster&7)))
if (lvis[cluster>>3] & /*vvis[cluster>>3] &*/ (1<<(cluster&7)))
{
node = (mnode_t *)leaf;
do
@ -1363,77 +1363,91 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
if (dl->worldshadowmesh && !dl->rebuildcache && dl->worldshadowmesh->type == type)
return dl->worldshadowmesh;
if (!lvis)
{
int leaf;
leaf = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, dl->origin);
lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb, sizeof(lvisb));
}
firstedge=0;
if (cl.worldmodel->type == mod_brush)
switch(cl.worldmodel->fromgame)
{
case fg_quake:
case fg_halflife:
/*if (!dl->die)
{
SHM_BeginShadowMesh(dl, true);
SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
if (!surfonly)
SHM_ComposeVolume_BruteForce(dl);
}
else*/
switch(cl.worldmodel->fromgame)
{
case fg_quake:
case fg_halflife:
/*if (!dl->die)
{
SHM_BeginShadowMesh(dl, true);
SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
if (!surfonly)
SHM_ComposeVolume_BruteForce(dl);
}
else*/
{
SHM_BeginShadowMesh(dl, type);
#if 0
{
int i;
msurface_t *surf;
for (i = 0; i < cl.worldmodel->numsurfaces; i+=2)
{
surf = &cl.worldmodel->surfaces[i];
SHM_Shadow_Cache_Surface(surf);
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
}
memset(sh_shmesh->litleaves, 0xff, sh_shmesh->leafbytes);
}
#else
SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
#endif
}
break;
#ifdef Q2BSPS
case fg_quake2:
SHM_BeginShadowMesh(dl, type);
SHM_MarkLeavesQ2(dl, lvis, vvis);
SHM_RecursiveWorldNodeQ2_r(dl, cl.worldmodel->nodes);
break;
#endif
#ifdef Q3BSPS
case fg_quake3:
/*q3 doesn't have edge info*/
SHM_BeginShadowMesh(dl, type);
#if 0
{
int i;
msurface_t *surf;
for (i = 0; i < cl.worldmodel->numsurfaces; i+=2)
{
surf = &cl.worldmodel->surfaces[i];
SHM_Shadow_Cache_Surface(surf);
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
int i;
msurface_t *surf;
for (i = 0; i < cl.worldmodel->numsurfaces; i++)
{
surf = &cl.worldmodel->surfaces[i];
SHM_Shadow_Cache_Surface(surf);
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
}
memset(sh_shmesh->litleaves, 0xff, sh_shmesh->leafbytes);
}
memset(sh_shmesh->litleaves, 0xff, sh_shmesh->leafbytes);
}
#else
SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
sh_shadowframe++;
SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes);
if (type == SMT_STENCILVOLUME)
SHM_ComposeVolume_BruteForce(dl);
#endif
break;
#endif
default:
return NULL;
}
break;
#ifdef Q2BSPS
case fg_quake2:
}
else
{
SHM_BeginShadowMesh(dl, type);
SHM_MarkLeavesQ2(dl, lvis, vvis);
SHM_RecursiveWorldNodeQ2_r(dl, cl.worldmodel->nodes);
break;
#endif
#ifdef Q3BSPS
case fg_quake3:
/*q3 doesn't have edge info*/
SHM_BeginShadowMesh(dl, type);
#if 0
{
int i;
msurface_t *surf;
for (i = 0; i < cl.worldmodel->numsurfaces; i++)
{
surf = &cl.worldmodel->surfaces[i];
SHM_Shadow_Cache_Surface(surf);
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
}
memset(sh_shmesh->litleaves, 0xff, sh_shmesh->leafbytes);
}
#else
sh_shadowframe++;
SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes);
if (type == SMT_STENCILVOLUME)
SHM_ComposeVolume_BruteForce(dl);
#endif
break;
#endif
default:
return NULL;
}
/*generate edge polys for map types that need it (q1/q2)*/
@ -2033,11 +2047,11 @@ void GL_BeginRenderBuffer_DepthOnly(texid_t depthtexture)
}
}
#endif
void GL_EndRenderBuffer_DepthOnly(texid_t depthtexture, int texsize)
void GL_EndRenderBuffer_DepthOnly(int restorefbo, texid_t depthtexture, int texsize)
{
if (gl_config.ext_framebuffer_objects)
{
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, restorefbo);
}
else
{
@ -2047,6 +2061,7 @@ void GL_EndRenderBuffer_DepthOnly(texid_t depthtexture, int texsize)
}
//determine the 5 bounding points of a shadowmap light projection side
//needs to match Sh_GenShadowFace
static void Sh_LightFrustumPlanes(dlight_t *l, vec4_t *planes, int face)
{
vec3_t tmp;
@ -2075,64 +2090,86 @@ static void Sh_LightFrustumPlanes(dlight_t *l, vec4_t *planes, int face)
}
}
//culling for the face happens in the caller.
//these faces should thus match Sh_LightFrustumPlanes
static void Sh_GenShadowFace(dlight_t *l, shadowmesh_t *smesh, int face, int smsize, float proj[16])
{
vec3_t t1,t2;
vec3_t t1,t2,t3;
texture_t *tex;
int tno;
//FIXME: figure out the four lines bounding the light cone by just adding its +forward+/-right+/-up values. if any point towards a plane (and starts outside that plane), and the point of intersection with that line and the frustum side plane is infront of the near clip plane, then that light frustum needs to be rendered...
switch(face)
{
case 0:
//+x - forward
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, l->axis[0], l->axis[1], l->axis[2], l->origin);
//down
VectorCopy(l->axis[0], t1);
VectorCopy(l->axis[1], t2);
VectorCopy(l->axis[2], t3);
Matrix4x4_CM_LightMatrixFromAxis(r_refdef.m_view, t1, t2, t3, l->origin);
r_refdef.flipcull = 0;
break;
case 1:
//+y - right
VectorNegate(l->axis[0], t1);
VectorNegate(l->axis[1], t2);
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, t2, t1, l->axis[2], l->origin);
//back
VectorCopy(l->axis[2], t1);
VectorCopy(l->axis[1], t2);
VectorCopy(l->axis[0], t3);
Matrix4x4_CM_LightMatrixFromAxis(r_refdef.m_view, t1, t2, t3, l->origin);
r_refdef.flipcull = SHADER_CULL_FLIP;
break;
case 2:
//+z - down
VectorNegate(l->axis[0], t1);
VectorNegate(l->axis[2], t2);
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, t2, l->axis[1], t1, l->origin);
//right
VectorCopy(l->axis[0], t1);
VectorCopy(l->axis[2], t2);
VectorCopy(l->axis[1], t3);
Matrix4x4_CM_LightMatrixFromAxis(r_refdef.m_view, t1, t2, t3, l->origin);
r_refdef.flipcull = SHADER_CULL_FLIP;
break;
case 3:
//-x - back
VectorNegate(l->axis[0], t1);
// VectorNegate(l->axis[1], t2);
// VectorNegate(l->axis[2], t3);
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, t1, l->axis[1], l->axis[2], l->origin);
//up
VectorCopy(l->axis[0], t1);
VectorCopy(l->axis[1], t2);
VectorCopy(l->axis[2], t3);
VectorNegate(t3, t3);
Matrix4x4_CM_LightMatrixFromAxis(r_refdef.m_view, t1, t2, t3, l->origin);
r_refdef.flipcull = SHADER_CULL_FLIP;
break;
case 4:
//-y - left
VectorNegate(l->axis[1], t1);
VectorNegate(l->axis[0], t2);
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, l->axis[1], t2, l->axis[2], l->origin);
//forward
VectorCopy(l->axis[2], t1);
VectorCopy(l->axis[1], t2);
VectorCopy(l->axis[0], t3);
VectorNegate(t3, t3);
Matrix4x4_CM_LightMatrixFromAxis(r_refdef.m_view, t1, t2, t3, l->origin);
r_refdef.flipcull = 0;
break;
case 5:
//-z - up
VectorNegate(l->axis[0], t2);
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, l->axis[2], l->axis[1], t2, l->origin);
//left
VectorCopy(l->axis[0], t1);
VectorCopy(l->axis[2], t2);
VectorCopy(l->axis[1], t3);
VectorNegate(t3, t3);
Matrix4x4_CM_LightMatrixFromAxis(r_refdef.m_view, t1, t2, t3, l->origin);
r_refdef.flipcull = 0;
break;
}
if (l->fov)
qglViewport (0, 0, smsize, smsize);
{
r_refdef.pxrect.x = 0;
r_refdef.pxrect.width = smsize;
r_refdef.pxrect.height = smsize;
r_refdef.pxrect.y = 0;
}
else
{
qglViewport ((face%3 * SHADOWMAP_SIZE) + (SHADOWMAP_SIZE-smsize)/2, ((face>=3)*SHADOWMAP_SIZE) + (SHADOWMAP_SIZE-smsize)/2, smsize, smsize);
r_refdef.pxrect.x = (face%3 * SHADOWMAP_SIZE) + (SHADOWMAP_SIZE-smsize)/2;
r_refdef.pxrect.width = smsize;
r_refdef.pxrect.height = smsize;
r_refdef.pxrect.y = r_refdef.pxrect.height - (((face>=3)*SHADOWMAP_SIZE) + (SHADOWMAP_SIZE-smsize)/2);
}
qglViewport (r_refdef.pxrect.x, r_refdef.pxrect.height-r_refdef.pxrect.y, r_refdef.pxrect.width, r_refdef.pxrect.height);
R_SetFrustum(proj, r_refdef.m_view);
#ifdef DBG_COLOURNOTDEPTH
@ -2210,8 +2247,10 @@ static void Sh_GenShadowFace(dlight_t *l, shadowmesh_t *smesh, int face, int sms
qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize)
{
int restorefbo;
int f;
float oproj[16], oview[16];
vrect_t oprect;
shadowmesh_t *smesh;
int isspot = (l->fov != 0);
extern cvar_t r_shadow_shadowmapping_precision;
@ -2231,11 +2270,11 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize)
float dist;
int fp,lp;
Sh_LightFrustumPlanes(l, planes, f);
for (fp = 0; fp < FRUSTUMPLANES; fp++)
for (fp = 0; fp < r_refdef.frustum_numplanes; fp++)
{
vec3_t nearest;
//make a guess based upon the frustum plane
VectorMA(l->origin, l->radius, frustum[fp].normal, nearest);
VectorMA(l->origin, l->radius, r_refdef.frustum[fp].normal, nearest);
//clip that point to the various planes
for(lp = 0; lp < 5; lp++)
@ -2247,11 +2286,11 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize)
// P_RunParticleEffect(nearest, vec3_origin, 15, 1);
//give up if the best point for any frustum plane is offscreen
dist = DotProduct(frustum[fp].normal, nearest) - frustum[fp].dist;
dist = DotProduct(r_refdef.frustum[fp].normal, nearest) - r_refdef.frustum[fp].dist;
if (dist <= 0)
break;
}
if (fp == FRUSTUMPLANES)
if (fp == r_refdef.frustum_numplanes)
sidevisible |= 1u<<f;
}
}
@ -2299,11 +2338,11 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize)
qglTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
}
smesh = SHM_BuildShadowMesh(l, lvis, NULL, true);
smesh = SHM_BuildShadowMesh(l, lvis, NULL, SMT_SHADOWMAP);
/*set framebuffer*/
GL_BeginRenderBuffer_DepthOnly(shadowmap[isspot]);
GLBE_SetupForShadowMap(shadowmap[isspot], isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
restorefbo = GLBE_SetupForShadowMap(shadowmap[isspot], isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
BE_Scissor(NULL);
qglViewport(0, 0, smsize*3, smsize*2);
@ -2315,6 +2354,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize)
memcpy(oproj, r_refdef.m_projection, sizeof(oproj));
memcpy(oview, r_refdef.m_view, sizeof(oview));
oprect = r_refdef.pxrect;
Matrix4x4_CM_Projection_Far(r_refdef.m_projection, l->fov?l->fov:90, l->fov?l->fov:90, r_shadow_shadowmapping_nearclip.value, l->radius);
if (!gl_config.nofixedfunc)
@ -2337,10 +2377,11 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize)
}
/*end framebuffer*/
GL_EndRenderBuffer_DepthOnly(shadowmap[isspot], smsize);
GL_EndRenderBuffer_DepthOnly(restorefbo, shadowmap[isspot], smsize);
memcpy(r_refdef.m_view, oview, sizeof(r_refdef.m_view));
memcpy(r_refdef.m_projection, oproj, sizeof(r_refdef.m_projection));
r_refdef.pxrect = oprect;
if (!gl_config.nofixedfunc)
{
@ -2350,7 +2391,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize)
qglLoadMatrixf(r_refdef.m_view);
}
qglViewport(r_refdef.pxrect.x, vid.pixelheight - r_refdef.pxrect.y, r_refdef.pxrect.width, r_refdef.pxrect.height);
qglViewport(r_refdef.pxrect.x, r_refdef.pxrect.y-r_refdef.pxrect.height, r_refdef.pxrect.width, r_refdef.pxrect.height);
r_refdef.flipcull = oldflip;
r_refdef.externalview = oldexternalview;
@ -2363,7 +2404,6 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, qbyte *vvis)
{
vec3_t mins, maxs;
qbyte *lvis;
qbyte lvisb[MAX_MAP_LEAFS/8];
srect_t rect;
int smsize;
@ -2647,7 +2687,7 @@ static void Sh_DrawStencilLightShadows(dlight_t *dl, qbyte *lvis, qbyte *vvis, q
struct shadowmesh_s *sm;
entity_t *ent;
sm = SHM_BuildShadowMesh(dl, lvis, vvis, false);
sm = SHM_BuildShadowMesh(dl, lvis, vvis, SMT_STENCILVOLUME);
if (!sm)
Sh_DrawBrushModelShadow(dl, &r_worldentity);
else
@ -2729,8 +2769,6 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, qbyte *vvis)
qbyte *lvis;
srect_t rect;
qbyte lvisb[MAX_MAP_LEAFS/8];
vec3_t mins;
vec3_t maxs;
@ -2986,12 +3024,11 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, qbyte *vvis)
{
int leaf;
qbyte *lvis;
qbyte lvisb[MAX_MAP_LEAFS/8];
leaf = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, dl->origin);
lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb, sizeof(lvisb));
SHM_BuildShadowMesh(dl, lvis, vvis, true);
SHM_BuildShadowMesh(dl, lvis, vvis, SMT_SHADOWLESS);
if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect.
{
@ -3124,6 +3161,7 @@ void Sh_PurgeShadowMeshes(void)
{
SH_FreeShadowMesh(dl->worldshadowmesh);
dl->worldshadowmesh = NULL;
dl->rebuildcache = true;
}
}
}
@ -3135,7 +3173,6 @@ void Sh_PreGenerateLights(void)
int shadowtype;
int leaf;
qbyte *lvis;
qbyte lvisb[MAX_MAP_LEAFS/8];
int i;
if (r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival)
@ -3150,6 +3187,8 @@ void Sh_PreGenerateLights(void)
for (dl = cl_dlights+rtlights_first, i=rtlights_first; i<rtlights_max; i++, dl++)
{
dl->rebuildcache = true;
if (dl->radius)
{
if (dl->flags & ignoreflags)
@ -3157,7 +3196,7 @@ void Sh_PreGenerateLights(void)
if (dl->flags & LFLAG_CREPUSCULAR)
continue;
if (((!dl->die)?!r_shadow_realtime_world_shadows.ival:!r_shadow_realtime_dlight_shadows.ival) || dl->flags & LFLAG_NOSHADOWS)
if (((!dl->die)?!r_shadow_realtime_world_shadows.ival:!r_shadow_realtime_dlight_shadows.ival) || (dl->flags & LFLAG_NOSHADOWS))
shadowtype = SMT_SHADOWLESS;
else if (dl->flags & LFLAG_SHADOWMAP || r_shadow_shadowmapping.ival)
shadowtype = SMT_SHADOWMAP;
@ -3198,43 +3237,33 @@ void Sh_DrawLights(qbyte *vis)
int i;
unsigned int ignoreflags;
if (!r_shadow_realtime_world.ival && !r_shadow_realtime_dlight.ival)
{
return;
}
if (r_shadow_realtime_world.modified ||
r_shadow_realtime_dlight_shadows.modified ||
r_shadow_realtime_dlight.modified ||
r_shadow_realtime_dlight_shadows.modified ||
r_shadow_shadowmapping.modified)
{
r_shadow_realtime_world.modified =
r_shadow_realtime_dlight_shadows.modified =
r_shadow_realtime_dlight.modified =
r_shadow_realtime_dlight_shadows.modified =
r_shadow_shadowmapping.modified =
false;
//make sure the lighting is reloaded
Sh_PreGenerateLights();
}
switch(qrenderer)
{
#ifdef GLQUAKE
case QR_OPENGL:
/*no stencil?*/
/*if (!gl_config.arb_shader_objects)
{
Con_Printf("Missing GL extensions: switching off realtime lighting.\n");
r_shadow_realtime_world.ival = 0;
r_shadow_realtime_dlight.ival = 0;
return;
}*/
if (r_shadow_shadowmapping.ival)
{ //if we've no glsl or fbos, shadowmapping ain't possible, so don't use it.
if (!gl_config.arb_shader_objects || !gl_config.ext_framebuffer_objects || !gl_config.arb_shadow)
{
//disable stuff if we can't cope with it
Con_Printf("Missing GL extensions: switching off shadowmapping.\n");
r_shadow_shadowmapping.ival = 0;
}
}
if (!r_shadow_shadowmapping.ival)
{ //if we're using stencil shadows, give up if there's no stencil buffer
if (!gl_stencilbits)
{
Con_Printf("Missing GL extensions: switching off realtime lighting.\n");
r_shadow_realtime_world.ival = 0;
r_shadow_realtime_dlight.ival = 0;
}
}
break;
#endif
#ifdef D3D9QUAKE
case QR_DIRECT3D9:
r_shadow_shadowmapping.ival = 0;
#ifdef GLQUAKE
//the code still has a lot of ifdefs, so will crash if you try it in a merged build.
//its not really usable in d3d-only builds either, so no great loss.
@ -3246,8 +3275,30 @@ void Sh_DrawLights(qbyte *vis)
return;
}
if (r_shadow_realtime_world.modified ||
r_shadow_realtime_world_shadows.modified ||
r_shadow_realtime_dlight.modified ||
r_shadow_realtime_dlight_shadows.modified ||
r_shadow_shadowmapping.modified)
{
r_shadow_realtime_world.modified =
r_shadow_realtime_world_shadows.modified =
r_shadow_realtime_dlight.modified =
r_shadow_realtime_dlight_shadows.modified =
r_shadow_shadowmapping.modified =
false;
//make sure the lighting is reloaded
Sh_PreGenerateLights();
}
if (!r_shadow_realtime_world.ival && !r_shadow_realtime_dlight.ival)
{
return;
}
ignoreflags = (r_shadow_realtime_world.value?LFLAG_REALTIMEMODE:LFLAG_NORMALMODE);
// if (r_refdef.recurse)
for (dl = cl_dlights+rtlights_first, i=rtlights_first; i<rtlights_max; i++, dl++)
{
if (!dl->radius)
@ -3296,7 +3347,8 @@ void Sh_DrawLights(qbyte *vis)
}
}
if (1)
#ifdef GLQUAKE
if (gl_config.arb_shader_objects)
{
dlight_t sun = {0};
vec3_t sundir;
@ -3328,6 +3380,7 @@ void Sh_DrawLights(qbyte *vis)
}
}
}
#endif
BE_Scissor(NULL);

View File

@ -905,6 +905,9 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
qglBindVertexArray = NULL;
}
gl_config.arb_shadow = GL_CheckExtension("GL_ARB_shadow");
gl_config.arb_shadow |= GL_CheckExtension("GL_EXT_shadow_samplers"); //gles2
#ifndef GL_STATIC
if (GL_CheckExtension("GL_ARB_framebuffer_object"))
{
@ -1136,6 +1139,109 @@ static const char *glsl_hdrs[] =
"#endif\n"
"}\n"
,
"sys/pcf.h",
"#ifndef r_glsl_pcf\n"
"#define r_glsl_pcf 9\n"
"#endif\n"
"#if r_glsl_pcf < 1\n"
"#undef r_glsl_pcf\n"
"#define r_glsl_pcf 9\n"
"#endif\n"
"uniform vec4 l_shadowmapproj;\n" //light projection matrix info
"uniform vec2 l_shadowmapscale;\n" //xy are the texture scale, z is 1, w is the scale.
"vec3 ShadowmapCoord(void)\n"
"{\n"
"#ifdef SPOT\n"
//bias it. don't bother figuring out which side or anything, its not needed
//l_projmatrix contains the light's projection matrix so no other magic needed
"vtexprojcoord.z -= 0.015;\n"
"return (vtexprojcoord.xyz/vtexprojcoord.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
//"#elif defined(CUBESHADOW)\n"
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r
"#else\n"
//figure out which axis to use
//texture is arranged thusly:
//forward left up
//back right down
"vec3 dir = abs(vtexprojcoord.xyz);\n"
//assume z is the major axis (ie: forward from the light)
"vec3 t = vtexprojcoord.xyz;\n"
"float ma = dir.z;\n"
"vec3 axis = vec3(0.5/3.0, 0.5/2.0, 0.5);\n"
"if (dir.x > ma)\n"
"{\n"
"ma = dir.x;\n"
"t = vtexprojcoord.zyx;\n"
"axis.x = 0.5;\n"
"}\n"
"if (dir.y > ma)\n"
"{\n"
"ma = dir.y;\n"
"t = vtexprojcoord.xzy;\n"
"axis.x = 2.5/3.0;\n"
"}\n"
//if the axis is negative, flip it.
"if (t.z > 0.0)\n"
"{\n"
"axis.y = 1.5/2.0;\n"
"t.z = -t.z;\n"
"}\n"
//we also need to pass the result through the light's projection matrix too
//the 'matrix' we need only contains 5 actual values. and one of them is a -1. So we might as well just use a vec4.
//note: the projection matrix also includes scalers to pinch the image inwards to avoid sampling over borders, as well as to cope with non-square source image
//the resulting z is prescaled to result in a value between -0.5 and 0.5.
//also make sure we're in the right quadrant type thing
"return axis + ((l_shadowmapproj.xyz*t.xyz + vec3(0.0, 0.0, l_shadowmapproj.w)) / -t.z);\n"
"#endif\n"
"}\n"
"float ShadowmapFilter(sampler2DShadow samp)\n"
"{\n"
"vec3 shadowcoord = ShadowmapCoord();\n"
"#if 0\n"//def GL_ARB_texture_gather
"vec2 ipart, fpart;\n"
"#define dosamp(x,y) textureGatherOffset(s_t4, ipart.xy, vec2(x,y)))\n"
"vec4 tl = step(shadowcoord.z, dosamp(-1.0, -1.0));\n"
"vec4 bl = step(shadowcoord.z, dosamp(-1.0, 1.0));\n"
"vec4 tr = step(shadowcoord.z, dosamp(1.0, -1.0));\n"
"vec4 br = step(shadowcoord.z, dosamp(1.0, 1.0));\n"
//we now have 4*4 results, woo
//we can just average them for 1/16th precision, but that's still limited graduations
//the middle four pixels are 'full strength', but we interpolate the sides to effectively give 3*3
"vec4 col = vec4(tl.ba, tr.ba) + vec4(bl.rg, br.rg) + " //middle two rows are full strength
"mix(vec4(tl.rg, tr.rg), vec4(bl.ba, br.ba), fpart.y);\n" //top+bottom rows
"return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0));\n" //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds.
"#else\n"
"#define dosamp(x,y) shadow2D(samp, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r\n"
"float s = 0.0;\n"
"#if r_glsl_pcf >= 1 && r_glsl_pcf < 5\n"
"s += dosamp(0.0, 0.0);\n"
"return s;\n"
"#elif r_glsl_pcf >= 5 && r_glsl_pcf < 9\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"return s/5.0;\n"
"#else\n"
"s += dosamp(-1.0, -1.0);\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(-1.0, 1.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, -1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"s += dosamp(1.0, 1.0);\n"
"return s/9.0;\n"
"#endif\n"
"#endif\n"
"}\n"
,
NULL
};
@ -1296,7 +1402,7 @@ GLhandleARB GLSlang_CreateShader (char *name, int ver, char **precompilerconstan
"#ifdef FRAMEBLEND\n"
"attribute vec3 v_position2;\n"
"uniform vec2 e_vblend;\n"
"#define v_position ((v_position*e_vblend.x)+(v_position2*e_vblend.y))\n"
"#define v_position ((v_position1*e_vblend.x)+(v_position2*e_vblend.y))\n"
"#else\n"
"#define v_position v_position1\n"
"#endif\n"
@ -1429,7 +1535,7 @@ GLhandleARB GLSlang_CreateProgramObject (char *name, GLhandleARB vert, GLhandleA
qglAttachObjectARB(program, vert);
qglAttachObjectARB(program, frag);
qglBindAttribLocationARB(program, VATTR_VERTEX1, "v_position");
qglBindAttribLocationARB(program, VATTR_VERTEX1, "v_position1");
qglBindAttribLocationARB(program, VATTR_COLOUR, "v_colour");
#if MAXRLIGHTMAPS > 1
qglBindAttribLocationARB(program, VATTR_COLOUR2, "v_colour2");

View File

@ -118,7 +118,6 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
vid.pixelwidth = info->width;
vid.pixelheight = info->height;
vid.numpages = 3;
gl_canstencil = 0;
const EGLint attribs[] = {
EGL_RENDERABLE_TYPE, (sys_glesversion>=2)?EGL_OPENGL_ES2_BIT:EGL_OPENGL_ES_BIT,

View File

@ -206,6 +206,7 @@ typedef struct {
qboolean arb_texture_compression;
// qboolean arb_fragment_program;
qboolean arb_shader_objects;
qboolean arb_shadow;
qboolean ext_framebuffer_objects;
qboolean ext_stencil_wrap;
qboolean ext_packed_depth_stencil;
@ -276,8 +277,6 @@ extern vec3_t r_entorigin;
extern entity_t *currententity;
extern int r_visframecount; // ??? what difs?
extern int r_framecount;
#define FRUSTUMPLANES 5
extern mplane_t frustum[FRUSTUMPLANES];
extern float r_wateralphaval;
extern qboolean r_loadbumpmapping;

View File

@ -232,7 +232,7 @@ void QuaternionGLMatrix(float x, float y, float z, float w, vec4_t *GLM);
//void UploadTexture(hlmdl_tex_t *ptexture, qbyte *data, qbyte *pal);
/* HL drawing */
qboolean Mod_LoadHLModel (model_t *mod, void *buffer);
qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer);
void R_DrawHLModel(entity_t *curent);
/* physics stuff */

View File

@ -1709,12 +1709,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#ifdef PCF\n"
"uniform vec4 l_shadowmapproj; //light projection matrix info\n"
"uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale.\n"
"#endif\n"
"#ifdef PCF\n"
"vec3 ShadowmapCoord(void)\n"
"{\n"
"#ifdef SPOT\n"
@ -1814,6 +1808,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#ifdef OFFSETMAPPING\n"
"#include \"sys/offsetmapping.h\"\n"
"#endif\n"
"void main ()\n"
"{\n"
//read raw texture samples (offsetmapping munges the tex coords first)
@ -2036,16 +2031,67 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"varying vec2 lm;\n"
"varying vec4 vc;\n"
"#ifdef RTLIGHT\n"
"varying vec3 lightvector;\n"
// #if defined(SPECULAR) || defined(OFFSETMAPPING)
// varying vec3 eyevector;
// #endif
"#if defined(PCF) || defined(CUBE) || defined(SPOT)\n"
"varying vec4 vtexprojcoord;\n"
"#endif\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
"#ifdef RTLIGHT\n"
"uniform vec3 l_lightposition;\n"
// #if defined(SPECULAR) || defined(OFFSETMAPPING)
// uniform vec3 e_eyepos;
// #endif
"#if defined(PCF) || defined(CUBE) || defined(SPOT)\n"
"uniform mat4 l_cubematrix;\n"
"#endif\n"
"attribute vec3 v_normal;\n"
"attribute vec3 v_svector;\n"
"attribute vec3 v_tvector;\n"
"#endif\n"
"attribute vec2 v_texcoord;\n"
"attribute vec2 v_lmcoord;\n"
"attribute vec4 v_colour;\n"
"void main (void)\n"
"{\n"
"tc = v_texcoord.st;\n"
"lm = v_lmcoord.st;\n"
"vc = v_colour;\n"
"gl_Position = ftetransform();\n"
"#ifdef RTLIGHT\n"
//light position is in model space, which is handy.
"vec3 lightminusvertex = l_lightposition - v_position.xyz;\n"
//no bumpmapping, so we can just use distance without regard for actual surface direction. we still do scalecos stuff. you might notice it on steep slopes.
"lightvector = lightminusvertex;\n"
// lightvector.x = -dot(lightminusvertex, v_svector.xyz);
// lightvector.y = dot(lightminusvertex, v_tvector.xyz);
// lightvector.z = dot(lightminusvertex, v_normal.xyz);
// #if defined(SPECULAR)||defined(OFFSETMAPPING)
// vec3 eyeminusvertex = e_eyepos - v_position.xyz;
// eyevector.x = -dot(eyeminusvertex, v_svector.xyz);
// eyevector.y = dot(eyeminusvertex, v_tvector.xyz);
// eyevector.z = dot(eyeminusvertex, v_normal.xyz);
// #endif
"#if defined(PCF) || defined(SPOT) || defined(CUBE)\n"
//for texture projections/shadowmapping on dlights
"vtexprojcoord = (l_cubematrix*vec4(v_position.xyz, 1.0));\n"
"#endif\n"
"#endif\n"
"}\n"
"#endif\n"
@ -2062,17 +2108,68 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
//mix values
"uniform sampler2D s_t4;\n"
"#ifdef PCF\n"
"sampler2DShadow s_t5;\n"
"#include \"sys/pcf.h\"\n"
"#endif\n"
//light levels
"uniform vec4 e_lmscale;\n"
"#ifdef RTLIGHT\n"
"uniform float l_lightradius;\n"
"uniform vec3 l_lightcolour;\n"
"uniform vec3 l_lightcolourscale;\n"
"#endif\n"
"void main (void)\n"
"{\n"
"vec4 r;\n"
"vec4 m = texture2D(s_t4, lm);\n"
"gl_FragColor = fog4(vc*vec4(m.aaa,1.0)*(\n"
"texture2D(s_t0, tc)*m.r\n"
"+ texture2D(s_t1, tc)*m.g\n"
"+ texture2D(s_t2, tc)*m.b\n"
"+ texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b))\n"
"));\n"
"r = texture2D(s_t0, tc)*m.r;\n"
"r += texture2D(s_t1, tc)*m.g;\n"
"r += texture2D(s_t2, tc)*m.b;\n"
"r += texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b));\n"
//vertex colours provide a scaler that applies even through rtlights.
"r *= vc;\n"
"#ifdef RTLIGHT\n"
"vec3 nl = normalize(lightvector);\n"
"float colorscale = max(1.0 - (dot(lightvector, lightvector)/(l_lightradius*l_lightradius)), 0.0);\n"
"vec3 diff;\n"
// #ifdef BUMP
// colorscale *= (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(bumps, nl), 0.0));
// #else
"colorscale *= (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(vec3(0.0, 0.0, 1.0), nl), 0.0));\n"
// #endif
// #ifdef SPECULAR
// vec3 halfdir = normalize(normalize(eyevector) + nl);
// float spec = pow(max(dot(halfdir, bumps), 0.0), 32.0 * specs.a);
// diff += l_lightcolourscale.z * spec * specs.rgb;
// #endif
"#if defined(SPOT)\n"
"if (vtexprojcoord.w < 0.0) discard;\n"
"vec2 spot = ((vtexprojcoord.st)/vtexprojcoord.w);\n"
"colorscale *= 1.0-(dot(spot,spot));\n"
"#endif\n"
"#ifdef PCF\n"
"colorscale *= ShadowmapFilter(s_t5);\n"
"#endif\n"
"r.rgb *= colorscale * l_lightcolour;\n"
"gl_FragColor = fog4additive(r);\n"
"#else\n"
//lightmap is greyscale in m.a. probably we should just scale the texture mix, but precision errors when editing make me paranoid.
"r *= e_lmscale*vec4(m.aaa,1.0);\n"
"gl_FragColor = fog4(r);\n"
"#endif\n"
"}\n"
"#endif\n"
},

View File

@ -438,6 +438,25 @@ typedef struct {
float factor;
float unit;
} polyoffset_t;
enum
{
LSHADER_STANDARD=0u, //stencil or shadowless
LSHADER_CUBE=1u<<0, //has a cubemap
LSHADER_SMAP=1u<<1, //filter based upon 6 directions of a shadowmap
LSHADER_SPOT=1u<<2, //filter based upon a single spotlight shadowmap
LSHADER_MODES=1u<<3
};
enum
{
//low numbers are used for various rtlight mode combinations
bemoverride_crepuscular = LSHADER_MODES, //either black (non-sky) or a special crepuscular_sky shader
bemoverride_depthonly, //depth masked. replace if you want alpha test.
bemoverride_depthdark, //itself or a pure-black shader. replace for alpha test.
bemoverride_prelight, //prelighting
bemoverride_fog, //post-render volumetric fog
bemoverride_max
};
struct shader_s
{
char name[MAX_QPATH];
@ -446,14 +465,17 @@ struct shader_s
SUF_LIGHTMAP = 1<<0, //$lightmap passes are valid. otherwise collapsed to an rgbgen
SUF_2D = 1<<1 //any loaded textures will obey 2d picmips rather than 3d picmips
} usageflags; //
int uses;
int width;
int uses; //released when the uses drops to 0
int width; //when used as an image, this is the logical 'width' of the image
int height;
int numpasses;
texnums_t defaulttextures;
struct shader_s *next;
int id;
//end of shared fields.
shader_t *bemoverrides[bemoverride_max];
byte_vec4_t fog_color;
float fog_dist;
float portaldist;
@ -507,8 +529,9 @@ struct shader_s
bucket_t bucket;
};
#define MAX_SHADERS 2048 //fixme: this takes a lot of bss in the r_shaders list
extern shader_t *r_shaders;
extern unsigned int r_numshaders;
extern unsigned int r_maxshaders;
extern shader_t **r_shaders;
extern int be_maxpasses;
@ -552,15 +575,6 @@ mfog_t *CM_FogForOrigin(vec3_t org);
#define BEF_FORCECOLOURMOD 256 //q3 shaders default to 'rgbgen identity', and ignore ent colours. this forces ent colours to be considered
#define BEF_LINES 512 //draw line pairs instead of triangles.
enum
{
LSHADER_STANDARD, //stencil or shadowless
LSHADER_CUBE, //has a cubemap
LSHADER_SMAP, //shadowmap
LSHADER_SPOT, //spotlight+shadowmap
LSHADER_MODES
};
#ifdef GLQUAKE
void GLBE_Init(void);
void GLBE_Shutdown(void);
@ -650,7 +664,7 @@ void Sh_RegisterCvars(void);
//
void GLBE_PushOffsetShadow(qboolean foobar);
//sets up gl for depth-only FIXME
void GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, float shadowscale);
int GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, float shadowscale);
//Called from shadowmapping code into backend
void GLBE_BaseEntTextures(void);
void D3D9BE_BaseEntTextures(void);

View File

@ -215,7 +215,7 @@ r_part te_explosion
randomvel 0
lightradius 350
lightrgb 0.4 0.2 0.05
lightrgb 1.4 1.2 1.05
lighttime 0.5
lightradiusfade 350
lightrgbfade 2 2 2

View File

@ -3194,7 +3194,7 @@ QCC_ref_t *QCC_PR_GenerateAddressOf(QCC_ref_t *retbuf, QCC_ref_t *operand)
//&foo (or &((&foo)[5]), which is basically an array). the result is a temp and thus cannot be assigned to (but should be possible to dereference further).
return QCC_PR_BuildRef(retbuf,
REF_GLOBAL,
QCC_PR_Statement(&pr_opcodes[OP_GLOBALADDRESS], operand->base, QCC_SupplyConversion(operand->index, ev_integer, true), NULL),
QCC_PR_Statement(&pr_opcodes[OP_GLOBALADDRESS], operand->base, operand->index?QCC_SupplyConversion(operand->index, ev_integer, true):NULL, NULL),
NULL,
QCC_PR_PointerType(operand->cast),
true);
@ -6703,7 +6703,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
rhsr = QCC_PR_RefExpression (&rhsbuf, priority, exprflags | EXPR_DISALLOW_ARRAYASSIGN);
if (conditional&1)
QCC_PR_ParseWarning(WARN_ASSIGNMENTINCONDITIONAL, "Assignment in conditional");
QCC_PR_ParseWarning(WARN_ASSIGNMENTINCONDITIONAL, "suggest parenthesis for assignment used as truth value .");
rhsd = QCC_RefToDef(rhsr, true);

View File

@ -2124,7 +2124,7 @@ void NPP_MVDFlush(void)
sv.demostatevalid = true;
}
entnum = buffer[1] + (buffer[2]<<8);
// if (entnum < MAX_CLIENTS)
// if (entnum < svs.allocated_client_slots)
// break;
ent = &sv.demobaselines[entnum];

View File

@ -211,6 +211,8 @@ void PDECL ED_Spawned (struct edict_s *ent, int loading)
ent->xv->dimension_ghost = 0;
ent->xv->dimension_solid = 255;
ent->xv->dimension_hit = 255;
if (progstype != PROG_H2)
ent->xv->drawflags = SCALE_ORIGIN_ORIGIN; //if not running hexen2, default the scale origin to the actual origin.
ent->xv->Version = sv.csqcentversion[ent->entnum];
ent->xv->uniquespawnid = sv.csqcentversion[ent->entnum];
@ -432,7 +434,7 @@ void PDECL PR_SSQC_Relocated(pubprogfuncs_t *pr, char *oldb, char *newb, int old
if (sv.strings.model_precache[i] >= oldb && sv.strings.model_precache[i] < oldb+oldlen)
sv.strings.model_precache[i] += newb - oldb;
}
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].name >= oldb && svs.clients[i].name < oldb+oldlen)
svs.clients[i].name += newb - oldb;
@ -6762,7 +6764,7 @@ void SV_AddDebugPolygons(void)
if (gfuncs.AddDebugPolygons)
{
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv.world.edicts);
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < sv.allocated_client_slots; i++)
if (svs.clients[i].netchan.remote_address.type == NA_LOOPBACK)
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict);
PR_ExecuteProgram (svprogfuncs, gfuncs.AddDebugPolygons);
@ -9554,7 +9556,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"isdemo", PF_Fixme, 0, 0, 0, 349, D("float()", "Returns if the client is currently playing a demo or not")},// (EXT_CSQC)
{"isserver", PF_Fixme, 0, 0, 0, 350, D("float()", "Returns if the client is acting as the server (aka: listen server)")},//(EXT_CSQC)
{"SetListener", PF_Fixme, 0, 0, 0, 351, D("void(vector origin, vector forward, vector right, vector up)", "Sets the position of the view, as far as the audio subsystem is concerned. This should be called once per CSQC_UpdateView as it will otherwise revert to default.")},// (EXT_CSQC)
{"SetListener", PF_Fixme, 0, 0, 0, 351, D("void(vector origin, vector forward, vector right, vector up, float inwater)", "Sets the position of the view, as far as the audio subsystem is concerned. This should be called once per CSQC_UpdateView as it will otherwise revert to default.")},// (EXT_CSQC)
{"registercommand", PF_Fixme, 0, 0, 0, 352, D("void(string cmdname)", "Register the given console command, for easy console use.\nConsole commands that are later used will invoke CSQC_ConsoleCommand.")},//(EXT_CSQC)
{"wasfreed", PF_WasFreed,0, 0, 0, 353, D("float(entity ent)", "Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust.")},//(EXT_CSQC) (should be availabe on server too)
{"serverkey", PF_Fixme, 0, 0, 0, 354, D("string(string key)", "Look up a key in the server's public serverinfo string")},//

View File

@ -243,7 +243,7 @@ void SV_Loadgame_f(void)
for (clnum = 0; clnum < MAX_CLIENTS; clnum++) //clear the server for the level change.
for (clnum = 0; clnum < sv.allocated_client_slots; clnum++) //clear the server for the level change.
{
cl = &svs.clients[clnum];
if (cl->state <= cs_zombie)
@ -257,13 +257,7 @@ void SV_Loadgame_f(void)
if (version == 5 || version == 6)
{
slots = 1;
for (clnum = 1; clnum < MAX_CLIENTS; clnum++) //kick all players fully. Load only player 1.
{
cl = &svs.clients[clnum];
cl->istobeloaded = false;
cl->state = cs_free;
}
SV_UpdateMaxPlayers(1);
cl = &svs.clients[0];
#ifdef SERVERONLY
strcpy(cl->name, "");
@ -279,7 +273,7 @@ void SV_Loadgame_f(void)
for (; i < NUM_SPAWN_PARMS; i++)
cl->spawn_parms[i] = 0;
}
else //fte QuakeWorld saves ALL the clients on the server.
else //fte saves ALL the clients on the server.
{
fscanf (f, "%f\n", &tfloat);
slots = tfloat;
@ -289,6 +283,7 @@ void SV_Loadgame_f(void)
Con_Printf ("Corrupted save game");
return;
}
SV_UpdateMaxPlayers(slots);
for (clnum = 0; clnum < sv.allocated_client_slots; clnum++) //work out which players we had when we saved, and hope they accepted the reconnect.
{
cl = &svs.clients[clnum];
@ -311,12 +306,6 @@ void SV_Loadgame_f(void)
for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
fscanf (f, "%f\n", &cl->spawn_parms[i]);
}
for (clnum = sv.allocated_client_slots; clnum < MAX_CLIENTS; clnum++)
{ //cleanup.
cl = &svs.clients[clnum];
cl->istobeloaded = false;
cl->state = cs_free;
}
}
if (version == 5 || version == 6)
{
@ -431,7 +420,7 @@ void SV_Loadgame_f(void)
SV_LinkEdict (ent, false);
}
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<sv.allocated_client_slots ; i++)
{
ent = EDICT_NUM(svprogfuncs, i+1);
svs.clients[i].edict = ent;
@ -712,7 +701,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea
World_ClearWorld (&sv.world);
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<svs.allocated_client_slots ; i++)
{
if (i < sv.allocated_client_slots)
ent = EDICT_NUM(svprogfuncs, i+1);
@ -736,7 +725,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea
eval = PR_FindGlobal(svprogfuncs, "ClientReEnter", 0, NULL);
if (eval)
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<sv.allocated_client_slots ; i++)
{
if (svs.clients[i].spawninfo)
{
@ -1131,7 +1120,7 @@ void SV_Loadgame_f (void)
Con_TPrintf (STL_LOADGAMEFROM, filename);
for (clnum = 0; clnum < MAX_CLIENTS; clnum++) //clear the server for the level change.
for (clnum = 0; clnum < svs.allocated_client_slots; clnum++) //clear the server for the level change.
{
cl = &svs.clients[clnum];
if (cl->state <= cs_zombie)

View File

@ -769,7 +769,8 @@ typedef struct
struct ftenet_connections_s *sockets;
client_t clients[MAX_CLIENTS];
int allocated_client_slots;
client_t *clients;
int serverflags; // episode completion information
double last_heartbeat;

View File

@ -615,7 +615,7 @@ void SV_Map_f (void)
}
#endif
for (i=0 ; i<MAX_CLIENTS ; i++) //we need to drop all q2 clients. We don't mix q1w with q2.
for (i=0 ; i<svs.allocated_client_slots ; i++) //we need to drop all q2 clients. We don't mix q1w with q2.
{
if (svs.clients[i].state>cs_connected) //so that we don't send a datagram
svs.clients[i].state=cs_connected;
@ -627,7 +627,7 @@ void SV_Map_f (void)
SCR_ImageName(level);
#endif
for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
for (i=0, host_client = svs.clients ; i<svs.allocated_client_slots ; i++, host_client++)
{
/*pass the new map's name as an extension, so appropriate loading screens can be shown*/
if (ISNQCLIENT(host_client))
@ -649,7 +649,7 @@ void SV_Map_f (void)
SCR_SetLoadingFile("server spawned");
//SV_BroadcastCommand ("cmd new\n");
for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
for (i=0, host_client = svs.clients ; i<svs.allocated_client_slots ; i++, host_client++)
{ //this expanded code cuts out a packet when changing maps...
//but more usefully, it stops dp(and probably nq too) from timing out.
//make sure its all reset.
@ -690,7 +690,7 @@ void SV_Map_f (void)
if (isDedicated)
Mod_Flush(false);
Mod_Purge(MP_MAPCHANGED);
}
void SV_KillServer_f(void)
@ -1531,7 +1531,7 @@ void SV_Status_f (void)
{
Con_Printf ("frags userid address name rate ping drop qport dl%% dls\n");
Con_Printf ("----- ------ --------------- --------------- ---- ---- ----- ----- --- ----\n");
for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
for (i=0,cl=svs.clients ; i<svs.allocated_client_slots ; i++,cl++)
{
if (!cl->state)
continue;
@ -1607,7 +1607,7 @@ void SV_ConSay_f(void)
Q_strcat(text, p);
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
for (j = 0, client = svs.clients; j < svs.allocated_client_slots; j++, client++)
{
if (client->state == cs_free)
continue;
@ -2052,7 +2052,7 @@ void SV_Snap (int uid)
char checkname[MAX_OSPATH];
int i;
for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
for (i = 0, cl = svs.clients; i < svs.allocated_client_slots; i++, cl++)
{
if (!cl->state)
continue;
@ -2132,7 +2132,7 @@ void SV_SnapAll_f (void)
client_t *cl;
int i;
for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
for (i = 0, cl = svs.clients; i < svs.allocated_client_slots; i++, cl++)
{
if (cl->state < cs_connected || cl->spectator)
continue;

View File

@ -93,7 +93,7 @@ void SV_RecordDemo_f (void)
fwrite(mapname, 1, sizeof(char)*(strlen(mapname)+1), svdemofile);
for (clnum = 0; clnum < MAX_CLIENTS; clnum++) //clear the server so the clients reconnect and send nice fresh messages.
for (clnum = 0; clnum < svs.allocated_client_slots; clnum++) //clear the server so the clients reconnect and send nice fresh messages.
{
c = &svs.clients[clnum];
if (c->state <= cs_zombie)
@ -149,7 +149,7 @@ void SV_PlayDemo_f(void)
svs.demoplayback = true;
for (clnum = 0; clnum < MAX_CLIENTS; clnum++) //clear the server so new clients don't conflict.
for (clnum = 0; clnum < svs.allocated_client_slots; clnum++) //clear the server so new clients don't conflict.
{
c = &svs.clients[clnum];
if (c->state <= cs_zombie)
@ -266,7 +266,7 @@ void SV_LoadClientDemo_f (void)
memset(sv.demostate, 0, sizeof(entity_state_t)*MAX_EDICTS);
}
/*
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < svs.allocated_client_slots; i++)
{
host_client = &svs.clients[i];
if (host_client->state == cs_spawned)

View File

@ -513,9 +513,8 @@ void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
coorddata coordd[3];
coorddata angled[3];
static entity_state_t defaultbaseline;
if (from == &((edict_t*)NULL)->baseline)
from = &defaultbaseline;
from = &nullentitystate;
// send an update
bits = 0;
@ -865,7 +864,7 @@ static unsigned int SVFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *to
if (to->tagentity != from->tagentity || to->tagindex != from->tagindex)
bits |= UF_TAGINFO;
if (to->light[0] != from->light[0] || to->light[1] != from->light[1] || to->light[2] != from->light[2] || to->light[3] != from->light[3] || to->lightstyle != from->lightstyle || to->lightpflags != from->lightstyle)
if (to->light[0] != from->light[0] || to->light[1] != from->light[1] || to->light[2] != from->light[2] || to->light[3] != from->light[3] || to->lightstyle != from->lightstyle || to->lightpflags != from->lightpflags)
bits |= UF_LIGHT;
if (to->u.q1.traileffectnum != from->u.q1.traileffectnum)
@ -1123,7 +1122,7 @@ void SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t
if (!client->pendingentbits)
return;
if (client->delta_sequence <= 0)
if (client->delta_sequence < 0)
client->pendingentbits[0] = UF_REMOVE;
//if we're clearing the list and starting from scratch, just wipe all lingering state

View File

@ -552,7 +552,7 @@ void SV_UnspawnServer (void) //terminate the running server.
sv.csqcentversion = NULL;
}
}
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].frameunion.frames)
Z_Free(svs.clients[i].frameunion.frames);
@ -562,10 +562,42 @@ void SV_UnspawnServer (void) //terminate the running server.
*svs.clients[i].namebuf = '\0';
svs.clients[i].name = NULL;
}
free(svs.clients);
svs.clients = NULL;
svs.allocated_client_slots = 0;
SV_FlushLevelCache();
NET_CloseServer ();
}
void SV_UpdateMaxPlayers(int newmax)
{
int i;
if (newmax != svs.allocated_client_slots)
{
for (i = newmax; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].state)
SV_DropClient(&svs.clients[i]);
svs.clients[i].namebuf[0] = '\0'; //kill all bots
}
if (newmax)
svs.clients = realloc(svs.clients, newmax*sizeof(*svs.clients));
else
{
free(svs.clients);
svs.clients = NULL;
}
for (i = svs.allocated_client_slots; i < newmax; i++)
{
memset(&svs.clients[i], 0, sizeof(svs.clients[i]));
svs.clients[i].name = svs.clients[i].namebuf;
svs.clients[i].team = svs.clients[i].teambuf;
}
svs.allocated_client_slots = sv.allocated_client_slots = newmax;
}
sv.allocated_client_slots = svs.allocated_client_slots;
}
/*
================
SV_SpawnServer
@ -633,7 +665,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
Rank_Flush();
#endif
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].state && ISQWCLIENT(&svs.clients[i]))
ReloadRanking(&svs.clients[i], svs.clients[i].name);
@ -656,7 +688,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
svs.netprim.anglesize = 1;
}
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < svs.allocated_client_slots; i++)
{
svs.clients[i].datagram.prim = svs.netprim;
svs.clients[i].netchan.message.prim = svs.netprim;
@ -800,7 +832,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
#if defined(Q2BSPS)
if (usecinematic)
{
qboolean Mod_LoadQ2BrushModel (model_t *mod, void *buffer);
qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer);
extern model_t *loadmodel;
strcpy (sv.name, server);
@ -966,13 +998,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
Q1QVM_Shutdown();
#endif
for (i=0 ; i<MAX_CLIENTS ; i++) //server type changed, so we need to drop all clients. :(
{
if (svs.clients[i].state)
SV_DropClient(&svs.clients[i]);
svs.clients[i].namebuf[0] = '\0'; //kill all bots
}
SV_UpdateMaxPlayers(0);
}
svs.gametype = newgametype;
@ -1049,7 +1075,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
SCR_SetLoadingFile("clients");
#endif
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<svs.allocated_client_slots ; i++)
{
svs.clients[i].edict = NULL;
svs.clients[i].name = svs.clients[i].namebuf;
@ -1073,14 +1099,17 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
Cvar_Set(&coop, "1");
}
#endif
/*only make one slot for single-player*/
if (!isDedicated && !deathmatch.value && !coop.value)
sv.allocated_client_slots = 1;
else
sv.allocated_client_slots = QWMAX_CLIENTS;
if (sv_playerslots.ival > 0)
sv.allocated_client_slots = sv_playerslots.ival;
sv.allocated_client_slots = bound(1, sv.allocated_client_slots, MAX_CLIENTS); //bound it
i = sv_playerslots.ival;
else
{
/*only make one slot for single-player*/
if (!isDedicated && !deathmatch.value && !coop.value)
i = 1;
else
i = QWMAX_CLIENTS;
}
SV_UpdateMaxPlayers(i);
// leave slots at start for clients only
for (i=0 ; i<sv.allocated_client_slots ; i++)
@ -1116,27 +1145,21 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
memset(svs.clients[i].csqcentversions, 0, sizeof(*svs.clients[i].csqcentversions) * svs.clients[i].max_net_ents);
#endif
}
for (; i < MAX_CLIENTS; i++)
{
if (svs.clients[i].state)
SV_DropClient(&svs.clients[i]);
svs.clients[i].namebuf[0] = '\0'; //kill all bots
}
break;
case GT_QUAKE2:
#ifdef Q2SERVER
for (i=0 ; i<MAX_CLIENTS ; i++)
SV_UpdateMaxPlayers(svq2_maxclients);
for (i=0 ; i<sv.allocated_client_slots ; i++)
{
q2ent = Q2EDICT_NUM(i+1);
q2ent->s.number = i+1;
svs.clients[i].q2edict = q2ent;
}
sv.allocated_client_slots = svq2_maxclients;
#endif
break;
case GT_QUAKE3:
#ifdef Q3SERVER
sv.allocated_client_slots = 32;
SV_UpdateMaxPlayers(32);
#endif
break;
case GT_HALFLIFE:
@ -1145,9 +1168,9 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
#endif
break;
}
//fixme: properly kick any other clients (ie: without notifying gamecode).
//fixme: is this right?
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<sv.allocated_client_slots ; i++)
{
Q_strncpyz(svs.clients[i].name, Info_ValueForKey(svs.clients[i].userinfo, "name"), sizeof(svs.clients[i].namebuf));
Q_strncpyz(svs.clients[i].team, Info_ValueForKey(svs.clients[i].userinfo, "team"), sizeof(svs.clients[i].teambuf));
@ -1438,7 +1461,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
if (!startspot)
{
SV_FlushLevelCache(); //to make sure it's caught
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<sv.allocated_client_slots ; i++)
{
if (svs.clients[i].spawninfo)
Z_Free(svs.clients[i].spawninfo);

View File

@ -164,10 +164,11 @@ cvar_t fraglimit = CVARF("fraglimit", "" , CVAR_SERVERINFO);
cvar_t timelimit = CVARF("timelimit", "" , CVAR_SERVERINFO);
cvar_t teamplay = CVARF("teamplay", "" , CVAR_SERVERINFO);
cvar_t samelevel = CVARF("samelevel", "" , CVAR_SERVERINFO);
cvar_t sv_playerslots = CVARD("sv_playerslots", "", "Specify maximum number of player/spectator slots. This should generally be maxclients+maxspectators. Leave blank for a default value. Maximum value of "STRINGIFY(MAX_CLIENTS)".");
cvar_t maxclients = CVARAF("maxclients", "8",
"sv_maxclients", CVAR_SERVERINFO);
cvar_t maxspectators = CVARF("maxspectators", "8", CVAR_SERVERINFO);
cvar_t sv_playerslots = CVARAD("sv_playerslots", "",
"maxplayers", "Specify maximum number of player/spectator/bot slots, new value takes effect on the next map (this may result in players getting kicked). This should generally be maxclients+maxspectators. Leave blank for a default value.\nMaximum value of "STRINGIFY(MAX_CLIENTS)". Values above 16 will result in issues with vanilla NQ clients. Effective values other than 32 will result in issues with vanilla QW clients.");
cvar_t maxclients = CVARAFD("maxclients", "8",
"sv_maxclients", CVAR_SERVERINFO, "Specify the maximum number of players allowed on the server at once. Can be changed mid-map.");
cvar_t maxspectators = CVARFD("maxspectators", "8", CVAR_SERVERINFO, "Specify the maximum number of spectators allowed on the server at once. Can be changed mid-map.");
#ifdef SERVERONLY
cvar_t deathmatch = CVARF("deathmatch", "1", CVAR_SERVERINFO); // 0, 1, or 2
#else
@ -389,7 +390,7 @@ void SV_FinalMessage (char *message)
MSG_WriteString (&sv.datagram, message);
MSG_WriteByte (&sv.datagram, svc_disconnect);
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++)
if (cl->state >= cs_spawned)
if (ISNQCLIENT(cl) || ISQWCLIENT(cl))
Netchan_Transmit (&cl->netchan, sv.datagram.cursize
@ -2195,7 +2196,7 @@ client_t *SVC_DirectConnect(void)
newcl->userinfo[sizeof(newcl->userinfo)-1] = '\0';
// if there is already a slot for this ip, drop it
for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
for (i=0,cl=svs.clients ; i<svs.allocated_client_slots ; i++,cl++)
{
if (cl->state == cs_free)
continue;
@ -2945,7 +2946,7 @@ void SVC_ACK (void)
int slotnum;
char adr[MAX_ADR_SIZE];
for (slotnum = 0; slotnum < MAX_CLIENTS; slotnum++)
for (slotnum = 0; slotnum < svs.allocated_client_slots; slotnum++)
{
if (svs.clients[slotnum].state)
{
@ -3506,7 +3507,7 @@ qboolean SV_ReadPackets (float *delay)
int giveup = 5000; /*we're fucked if we need this to be this high, but at least we can retain some clients if we're really running that slow*/
int cookie = 0;
for (i = 0; i < MAX_CLIENTS; i++) //fixme: shouldn't we be using svs.allocated_client_slots ?
for (i = 0; i < svs.allocated_client_slots; i++) //fixme: shouldn't we be using svs.allocated_client_slots ?
{
cl = &svs.clients[i];
while (cl->laggedpacket)
@ -3613,7 +3614,7 @@ qboolean SV_ReadPackets (float *delay)
qport = MSG_ReadShort () & 0xffff;
// check for packets from connected clients
for (i=0, cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
for (i=0, cl=svs.clients ; i<svs.allocated_client_slots ; i++,cl++)
{
if (cl->state == cs_free)
continue;
@ -3701,7 +3702,7 @@ dominping:
break;
}
if (i != MAX_CLIENTS)
if (i != svs.allocated_client_slots)
continue;
#ifdef Q3SERVER
@ -3750,7 +3751,7 @@ void SV_CheckTimeouts (void)
droptime = realtime - timeout.value;
nclients = 0;
for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
for (i=0,cl=svs.clients ; i<svs.allocated_client_slots ; i++,cl++)
{
if (cl->state == cs_connected || cl->state == cs_spawned) {
if (!cl->spectator)
@ -3966,7 +3967,7 @@ static void SV_PauseChanged(void)
int i;
client_t *cl;
// send notification to all clients
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++)
{
if (!cl->state)
continue;
@ -4785,14 +4786,17 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
strcpy(newname, "unnamed");
// check to see if another user by the same name exists
while (1) {
for (i=0, client = svs.clients ; i<MAX_CLIENTS ; i++, client++) {
while (1)
{
for (i=0, client = svs.clients ; i<svs.allocated_client_slots ; i++, client++)
{
if (client->state < cs_connected || client == cl)
continue;
if (!stricmp(client->name, newname))
break;
}
if (i != MAX_CLIENTS) { // dup name
if (i != svs.allocated_client_slots)
{ // dup name
if (strlen(newname) > sizeof(cl->namebuf) - 1)
newname[sizeof(cl->namebuf) - 4] = 0;
p = newname;
@ -4808,7 +4812,8 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
memmove(newname+10, p, strlen(p)+1);
sprintf(newname, "(%d)%-.40s", dupc++, newname+10);
} else
}
else
break;
}
@ -4999,7 +5004,8 @@ void SV_Init (quakeparms_t *parms)
#ifdef TERRAIN
Terr_Init();
#endif
Mod_Init ();
Mod_Init (true);
Mod_Init (false);
PF_Common_RegisterCvars();
}

View File

@ -649,6 +649,11 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
continue;
}
//these pushes are contents brushes, and are not solid. water cannot crush. the player just enters the water.
//but, the player will be moved along with the water.
if (pusher->v->skin < 0)
continue;
// Con_Printf("Pusher hit %s\n", PR_GetString(w->progs, check->v->classname));
if (pusher->v->blocked)
{
@ -768,7 +773,14 @@ static qboolean WPhys_Push (world_t *w, wedict_t *pusher, vec3_t move, vec3_t am
// try moving the contacted entity
VectorAdd (check->v->origin, move, check->v->origin);
block = World_TestEntityPosition (w, check);
if (pusher->v->skin < 0)
{
pusher->v->solid = SOLID_NOT;
block = World_TestEntityPosition (w, check);
pusher->v->solid = oldsolid;
}
else
block = World_TestEntityPosition (w, check);
if (!block)
{ // pushed ok
World_LinkEdict (w, check, false);
@ -801,6 +813,11 @@ static qboolean WPhys_Push (world_t *w, wedict_t *pusher, vec3_t move, vec3_t am
continue;
}
//these pushes are contents brushes, and are not solid. water cannot crush. the player just enters the water.
//but, the player will be moved along with the water.
if (pusher->v->skin < 0)
continue;
VectorCopy (pushorig, pusher->v->origin);
World_LinkEdict (w, pusher, false);

View File

@ -379,7 +379,7 @@ void VARGS SV_BroadcastPrintf (int level, char *fmt, ...)
Sys_Printf ("%s", string); // print to the console
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++)
{
if (level < cl->messagelevel)
continue;
@ -422,7 +422,7 @@ void VARGS SV_BroadcastTPrintf (int level, translation_t stringnum, ...)
Sys_Printf ("%s", string); // print to the console
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++)
{
if (level < cl->messagelevel)
continue;
@ -584,7 +584,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
}
// send the data to all relevent clients
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
for (j = 0, client = svs.clients; j < svs.allocated_client_slots; j++, client++)
{
if (client->state != cs_spawned)
continue;
@ -729,7 +729,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
}
// send the data to all relevent clients
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
for (j = 0, client = svs.clients; j < sv.allocated_client_slots; j++, client++)
{
if (client->state != cs_spawned)
continue;
@ -897,7 +897,7 @@ void SV_StartSound (int ent, vec3_t origin, int seenmask, int channel, char *sam
if (channel & 256)
{
channel -= 256;
channel &= ~256;
reliable = true;
}
else
@ -1057,6 +1057,13 @@ void SVQ1_StartSound (float *origin, wedict_t *wentity, int channel, char *sampl
{
for (i=0 ; i<3 ; i++)
origin[i] = entity->v->origin[i]+0.5*(entity->v->mins[i]+entity->v->maxs[i]);
//add the reliable flag for bsp objects.
//these sounds are often looped, and if the start is in the phs and the end isn't/gets dropped, then you end up with an annoying infinitely looping sample.
//making them all reliable avoids packetloss and phs issues.
//this applies only to pushers. you won't get extra latency on player actions because of this.
//be warned that it does mean you might be able to hear people triggering stuff on the other side of the map however.
channel |= 256;
}
else
{
@ -1990,7 +1997,7 @@ void SV_FlushBroadcasts (void)
client_t *client;
int j;
// append the broadcast messages to each client messages
for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
for (j=0, client = svs.clients ; j<svs.allocated_client_slots ; j++, client++)
{
if (client->state < cs_connected)
continue; // reliables go to all connected or spawned
@ -2071,7 +2078,7 @@ void SV_UpdateToReliableMessages (void)
int curfrags;
// check for changes to be sent over the reliable streams to all clients
for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
for (i=0, host_client = svs.clients ; i<svs.allocated_client_slots ; i++, host_client++)
{
if ((svs.gametype == GT_Q1QVM || svs.gametype == GT_PROGS) && host_client->state == cs_spawned)
{
@ -2184,7 +2191,7 @@ void SV_UpdateToReliableMessages (void)
}
if (host_client->old_frags != curfrags)
{
for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
for (j=0, client = svs.clients ; j<sv.allocated_client_slots ; j++, client++)
{
if (client->state < cs_connected)
continue;
@ -2322,7 +2329,7 @@ void SV_SendClientMessages (void)
SV_UpdateToReliableMessages ();
// build individual updates
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
for (i=0, c = svs.clients ; i<svs.allocated_client_slots ; i++, c++)
{
if (c->state <= cs_zombie)
continue;
@ -2712,7 +2719,7 @@ void SV_SendMessagesToAll (void)
int i;
client_t *c;
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
for (i=0, c = svs.clients ; i<svs.allocated_client_slots ; i++, c++)
if (c->state) // FIXME: should this only send to active?
c->send_message = true;

View File

@ -1486,7 +1486,7 @@ void SVQW_Spawn_f (void)
// send current status of all other players
// normally this could overflow, but no need to check due to backbuf
for (i=0, client = svs.clients ; i<MAX_CLIENTS ; i++, client++)
for (i=0, client = svs.clients ; i<svs.allocated_client_slots ; i++, client++)
SV_FullClientUpdate(client, host_client);
SV_MVD_FullClientUpdate(NULL, host_client);
@ -3230,7 +3230,7 @@ void SV_Say (qboolean team)
mvdrecording = sv.mvdrecording;
sv.mvdrecording = false; //so that the SV_ClientPrintf doesn't send to all players.
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
for (j = 0, client = svs.clients; j < svs.allocated_client_slots; j++, client++)
{
if (client->state != cs_spawned && client->state != cs_connected)
continue;
@ -3321,7 +3321,7 @@ void SV_Pings_f (void)
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
{
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
for (j = 0, client = svs.clients; j < svs.allocated_client_slots; j++, client++)
{
if (!*sv.recordedplayer[j].userinfo)
continue;
@ -3340,7 +3340,7 @@ void SV_Pings_f (void)
char *s;
ClientReliableWrite_Begin(host_client, svc_stufftext, 15+10*MAX_CLIENTS);
ClientReliableWrite_SZ(host_client, "pingplreport", 12);
for (j = 0, client = svs.clients; j < MAX_CLIENTS && j < host_client->max_net_clients; j++, client++)
for (j = 0, client = svs.clients; j < sv.allocated_client_slots && j < host_client->max_net_clients; j++, client++)
{
s = va(" %i %i", SV_CalcPing(client, false), client->lossage);
ClientReliableWrite_SZ(host_client, s, strlen(s));
@ -3351,7 +3351,7 @@ void SV_Pings_f (void)
}
else
{
for (j = 0, client = svs.clients; j < MAX_CLIENTS && j < host_client->max_net_clients; j++, client++)
for (j = 0, client = svs.clients; j < sv.allocated_client_slots && j < host_client->max_net_clients; j++, client++)
{
if (client->state != cs_spawned)
continue;
@ -3687,7 +3687,7 @@ void SV_SetInfo_f (void)
basic = SV_UserInfoIsBasic(key);
for (j = 0; j < MAX_CLIENTS; j++)
for (j = 0; j < svs.allocated_client_slots; j++)
{
client = svs.clients+j;
if (client->state < cs_connected)
@ -5329,18 +5329,23 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
switch((int)check->v->skin)
{
case Q1CONTENTS_WATER:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_WATER;
break;
case Q1CONTENTS_LAVA:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_LAVA;
break;
case Q1CONTENTS_SLIME:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_SLIME;
break;
case Q1CONTENTS_SKY:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_SKY;
break;
case Q1CONTENTS_LADDER:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_LADDER;
break;
default:

View File

@ -265,7 +265,7 @@ hledict_t *QDECL GHL_FindClientInPVS(hledict_t *ed)
viewerpvs = sv.world.worldmodel->funcs.LeafPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.LeafnumForPoint(sv.world.worldmodel, ed->v.origin), NULL, 0);
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].state == cs_spawned)
{

View File

@ -204,7 +204,7 @@ void Mod_Init (void)
memset (mod_novis, 0xff, sizeof(mod_novis));
Cvar_Register(&sv_nogetlight, "Memory preservation");
Cvar_Register (&dpcompat_psa_ungroup, "Darkplaces compatibility");
Cvar_Register (&r_noframegrouplerp, "Oooga booga");
Cvar_Register (&r_noframegrouplerp, "Graphical Nicaties");
}
/*
@ -322,17 +322,17 @@ qbyte *Mod_LeafnumPVS (int ln, model_t *model, qbyte *buffer)
/*
===================
Mod_Flush
Mod_Purge
===================
*/
void Mod_Flush(qboolean force)
void Mod_Purge(enum mod_purge_e type)
{
int i;
model_t *mod;
for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
{
if (mod->datasequence != mod_datasequence || force)
if (mod->datasequence != mod_datasequence || type != MP_MAPCHANGED)
{
//and obliterate anything else remaining in memory.
ZG_FreeGroup(&mod->memgroup);
@ -1892,7 +1892,7 @@ qboolean Mod_LoadBrushModel (model_t *mod, void *buffer)
}
#ifdef TERRAIN
lm->terrain = Mod_LoadTerrainInfo(lm, loadname);
lm->terrain = Mod_LoadTerrainInfo(lm, loadname, false);
#endif
return true;

View File

@ -117,12 +117,6 @@ uniform vec3 l_lightcolourscale;
#ifdef PCF
uniform vec4 l_shadowmapproj; //light projection matrix info
uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale.
#endif
#ifdef PCF
vec3 ShadowmapCoord(void)
{
#ifdef SPOT
@ -222,6 +216,7 @@ float ShadowmapFilter(void)
#ifdef OFFSETMAPPING
#include "sys/offsetmapping.h"
#endif
void main ()
{
//read raw texture samples (offsetmapping munges the tex coords first)

View File

@ -4,16 +4,67 @@ varying vec2 tc;
varying vec2 lm;
varying vec4 vc;
#ifdef RTLIGHT
varying vec3 lightvector;
// #if defined(SPECULAR) || defined(OFFSETMAPPING)
// varying vec3 eyevector;
// #endif
#if defined(PCF) || defined(CUBE) || defined(SPOT)
varying vec4 vtexprojcoord;
#endif
#endif
#ifdef VERTEX_SHADER
#ifdef RTLIGHT
uniform vec3 l_lightposition;
// #if defined(SPECULAR) || defined(OFFSETMAPPING)
// uniform vec3 e_eyepos;
// #endif
#if defined(PCF) || defined(CUBE) || defined(SPOT)
uniform mat4 l_cubematrix;
#endif
attribute vec3 v_normal;
attribute vec3 v_svector;
attribute vec3 v_tvector;
#endif
attribute vec2 v_texcoord;
attribute vec2 v_lmcoord;
attribute vec4 v_colour;
void main (void)
{
tc = v_texcoord.st;
lm = v_lmcoord.st;
vc = v_colour;
gl_Position = ftetransform();
#ifdef RTLIGHT
//light position is in model space, which is handy.
vec3 lightminusvertex = l_lightposition - v_position.xyz;
//no bumpmapping, so we can just use distance without regard for actual surface direction. we still do scalecos stuff. you might notice it on steep slopes.
lightvector = lightminusvertex;
// lightvector.x = -dot(lightminusvertex, v_svector.xyz);
// lightvector.y = dot(lightminusvertex, v_tvector.xyz);
// lightvector.z = dot(lightminusvertex, v_normal.xyz);
// #if defined(SPECULAR)||defined(OFFSETMAPPING)
// vec3 eyeminusvertex = e_eyepos - v_position.xyz;
// eyevector.x = -dot(eyeminusvertex, v_svector.xyz);
// eyevector.y = dot(eyeminusvertex, v_tvector.xyz);
// eyevector.z = dot(eyeminusvertex, v_normal.xyz);
// #endif
#if defined(PCF) || defined(SPOT) || defined(CUBE)
//for texture projections/shadowmapping on dlights
vtexprojcoord = (l_cubematrix*vec4(v_position.xyz, 1.0));
#endif
#endif
}
#endif
@ -30,16 +81,67 @@ uniform sampler2D s_t3;
//mix values
uniform sampler2D s_t4;
#ifdef PCF
sampler2DShadow s_t5;
#include "sys/pcf.h"
#endif
//light levels
uniform vec4 e_lmscale;
#ifdef RTLIGHT
uniform float l_lightradius;
uniform vec3 l_lightcolour;
uniform vec3 l_lightcolourscale;
#endif
void main (void)
{
vec4 r;
vec4 m = texture2D(s_t4, lm);
gl_FragColor = fog4(vc*vec4(m.aaa,1.0)*(
texture2D(s_t0, tc)*m.r
+ texture2D(s_t1, tc)*m.g
+ texture2D(s_t2, tc)*m.b
+ texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b))
));
r = texture2D(s_t0, tc)*m.r;
r += texture2D(s_t1, tc)*m.g;
r += texture2D(s_t2, tc)*m.b;
r += texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b));
//vertex colours provide a scaler that applies even through rtlights.
r *= vc;
#ifdef RTLIGHT
vec3 nl = normalize(lightvector);
float colorscale = max(1.0 - (dot(lightvector, lightvector)/(l_lightradius*l_lightradius)), 0.0);
vec3 diff;
// #ifdef BUMP
// colorscale *= (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(bumps, nl), 0.0));
// #else
colorscale *= (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(vec3(0.0, 0.0, 1.0), nl), 0.0));
// #endif
// #ifdef SPECULAR
// vec3 halfdir = normalize(normalize(eyevector) + nl);
// float spec = pow(max(dot(halfdir, bumps), 0.0), 32.0 * specs.a);
// diff += l_lightcolourscale.z * spec * specs.rgb;
// #endif
#if defined(SPOT)
if (vtexprojcoord.w < 0.0) discard;
vec2 spot = ((vtexprojcoord.st)/vtexprojcoord.w);
colorscale *= 1.0-(dot(spot,spot));
#endif
#ifdef PCF
colorscale *= ShadowmapFilter(s_t5);
#endif
r.rgb *= colorscale * l_lightcolour;
gl_FragColor = fog4additive(r);
#else
//lightmap is greyscale in m.a. probably we should just scale the texture mix, but precision errors when editing make me paranoid.
r *= e_lmscale*vec4(m.aaa,1.0);
gl_FragColor = fog4(r);
#endif
}
#endif

View File

@ -94,6 +94,7 @@ static int64_t AVIO_Seek(void *opaque, int64_t offset, int whence)
{
struct decctx *ctx = opaque;
int64_t ret = ctx->fileofs;
whence &= ~AVSEEK_FORCE;
switch(whence)
{
case SEEK_SET:
@ -110,7 +111,7 @@ static int64_t AVIO_Seek(void *opaque, int64_t offset, int whence)
return ctx->filelen;
}
pFS_Seek(ctx->file, ctx->fileofs & 0xffffffff, ctx->fileofs>>32);
return ret;
return ctx->fileofs;
}
static void AVDec_Destroy(void *vctx)
@ -119,12 +120,14 @@ static void AVDec_Destroy(void *vctx)
// Free the video stuff
avpicture_free(&ctx->pFrameRGB);
if (ctx->pVCodecCtx)
avcodec_close(ctx->pVCodecCtx);
av_free(ctx->pVFrame);
avcodec_close(ctx->pVCodecCtx);
// Free the audio decoder
if (ctx->pACodecCtx)
avcodec_close(ctx->pACodecCtx);
av_free(ctx->pAFrame);
avcodec_close(ctx->pACodecCtx);
// Close the video file
avformat_close_input(&ctx->pFormatCtx);

View File

@ -379,7 +379,7 @@ int Base64_Decode(char *out, int outlen, char *src, int srclen)
void XMPP_Menu_Password(jclient_t *acc);
void RenameConsole(char *totrim);
void JCL_Command(int accid, char *consolename);
void JCL_LoadConfig(void);
@ -506,6 +506,9 @@ static int sasl_plain_initial(jclient_t *jcl, char *buf, int bufsize)
if (jcl->issecure?jcl->allowauth_plaintls:jcl->allowauth_plainnontls)
{
if (!*jcl->password)
return -2;
//realm isn't specified
buf[len++] = 0;
memcpy(buf+len, jcl->username, strlen(jcl->username));
@ -568,6 +571,9 @@ static int sasl_digestmd5_initial(jclient_t *jcl, char *buf, int bufsize)
{
if (jcl->allowauth_digestmd5)
{
if (!*jcl->password)
return -2;
//FIXME: randomize the cnonce and check the auth key
//although really I'm not entirely sure what the point is.
//if we just authenticated with a mitm attacker relay, we're screwed either way.
@ -645,6 +651,8 @@ static int sasl_scramsha1_initial(jclient_t *jcl, char *buf, int bufsize)
{
if (jcl->allowauth_scramsha1)
{
if (!*jcl->password)
return -2;
strcpy(jcl->authnonce, "abcdefghijklmnopqrstuvwxyz"); //FIXME: should be random, to validate that the server knows our password too
Q_snprintf(buf, bufsize, "n,,n=%s,r=%s", jcl->username, jcl->authnonce);
@ -1091,10 +1099,10 @@ static int sasl_oauth2_initial(jclient_t *jcl, char *buf, int bufsize)
//in descending priority order
saslmethod_t saslmethods[] =
{
{NULL, sasl_oauth2_initial, NULL}, //potentially avoids having to ask+store their password. a browser is required to obtain auth token for us.
{"SCRAM-SHA-1", sasl_scramsha1_initial, sasl_scramsha1_challenge}, //lots of unreadable hashing
{"DIGEST-MD5", sasl_digestmd5_initial, sasl_digestmd5_challenge}, //kinda silly
{"PLAIN", sasl_plain_initial, NULL} //realm\0username\0password
{"PLAIN", sasl_plain_initial, NULL}, //realm\0username\0password
{NULL, sasl_oauth2_initial, NULL} //potentially avoids having to ask+store their password. a browser is required to obtain auth token for us.
};
/*
@ -1217,6 +1225,22 @@ qintptr_t JCL_ConsoleLink(qintptr_t *args)
JCL_AddClientMessagef(jcl, "<presence to='%s' type='unsubscribed'/>", who);
return true;
}
#ifdef FILETRANSFERS
else if (!strcmp(what, "fauth"))
{
JCL_Info_ValueForKey(link, "xmppsid", what, sizeof(what));
if (jcl && jcl->status == JCL_ACTIVE)
JCL_FT_AcceptFile(jcl, atoi(what), true);
return true;
}
else if (!strcmp(what, "fdeny"))
{
JCL_Info_ValueForKey(link, "xmppsid", what, sizeof(what));
if (jcl && jcl->status == JCL_ACTIVE)
JCL_FT_AcceptFile(jcl, atoi(what), false);
return true;
}
#endif
#ifdef JINGLE
else if (!strcmp(what, "jauth"))
{
@ -1287,28 +1311,38 @@ qintptr_t JCL_ConExecuteCommand(qintptr_t *args)
{
buddy_t *b;
char consolename[256];
jclient_t *jcl = jclients[0];
jclient_t *jcl;
int i;
if (!jcl)
{
char buffer[256];
pCmd_Argv(0, buffer, sizeof(buffer));
Con_SubPrintf(buffer, "You were disconnected\n");
return true;
}
pCmd_Argv(0, consolename, sizeof(consolename));
for (b = jcl->buddies; b; b = b->next)
for (i = 0; i < sizeof(jclients) / sizeof(jclients[0]); i++)
{
if (!strcmp(b->name, consolename))
jcl = jclients[i];
if (!jcl)
continue;
for (b = jcl->buddies; b; b = b->next)
{
if (b->defaultresource)
Q_snprintf(jcl->defaultdest, sizeof(jcl->defaultdest), "%s/%s", b->accountdomain, b->defaultresource->resource);
else
Q_snprintf(jcl->defaultdest, sizeof(jcl->defaultdest), "%s", b->accountdomain);
break;
if (!strcmp(b->name, consolename))
{
if (b->defaultresource)
Q_snprintf(jcl->defaultdest, sizeof(jcl->defaultdest), "%s/%s", b->accountdomain, b->defaultresource->resource);
else
Q_snprintf(jcl->defaultdest, sizeof(jcl->defaultdest), "%s", b->accountdomain);
JCL_Command(i, consolename);
return true;
}
}
}
JCL_Command(0, consolename);
for (i = 0; i < sizeof(jclients) / sizeof(jclients[0]); i++)
{
jcl = jclients[i];
if (!jcl)
continue;
JCL_Command(i, consolename);
return true;
}
Con_SubPrintf(consolename, "You were disconnected\n");
return true;
}
@ -1613,7 +1647,7 @@ jclient_t *JCL_Connect(int accnum, char *server, int forcetls, char *account, ch
xmltree_t *x;
res = TrimResourceFromJid(account);
if (!res)
if (!res || !*res)
{
//the default resource matches the game that they're trying to play.
if (pCvar_GetString("fs_gamename", gamename, sizeof(gamename)))
@ -1946,11 +1980,11 @@ static char *caps[] =
"urn:xmpp:attention:0", //poke.
//file transfer
#ifdef FILETRANSFER
#ifdef FILETRANSFERS
"http://jabber.org/protocol/si",
"http://jabber.org/protocol/si/profile/file-transfer",
"http://jabber.org/protocol/ibb",
//"http://jabber.org/protocol/bytestreams",
"http://jabber.org/protocol/bytestreams",
#endif
#else
//for testing, this is the list of features pidgin supports (which is the other client I'm testing against).
@ -2202,6 +2236,64 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree)
{
xmltree_t *c;
#ifdef FILETRANSFERS
/*
ot = XML_ChildOfTreeNS(tree, "http://jabber.org/protocol/bytestreams", "query", 0);
if (ot)
{
struct ft_s *ft;
char *sid = XML_GetParameter(ot, "sid", "");
for (ft = jcl->ft; ft; ft = ft->next)
{
if (!strcmp(ft->sid, sid) && !strcmp(ft->with, from))
{
if (ft->allowed && !ft->begun && ft->transmitting == false)
{
char *jid;
char *host;
int port;
char *req;
char digest[20];
char domain[41];
char *hex="0123456789abcdef";
int j, i;
for (i = 0; ; i++)
{
c = XML_ChildOfTree(ot, "streamhost", i);
if (!c)
break;
jid = XML_GetParameter(c, "jid", "");
host = XML_GetParameter(c, "host", "");
port = atoi(XML_GetParameter(c, "port", "0"));
if (port <= 0 || port > 65535)
continue;
ft->stream = pNet_TCPConnect(host, port);
if (ft->stream == -1)
continue;
//'authenticate' with socks5 proxy.
pNet_Send(ft->stream, "\x05\0x1\x00", 3);
//sid+requester(them)+target(us)
req = va("%s%s%s", ft->sid, ft->with, jcl->jid);
SHA1(digest, sizeof(digest), req, strlen(req));
//in hex
for (req = domain, j=0; j < 20; j++)
{
*req++ = hex[(digest[j]>>4) & 0xf];
*req++ = hex[(digest[j]>>0) & 0xf];
}
*req = 0;
//connect with hostname(3).
req = va("\x05\0x1\x00\x03%s\x00\x00", domain);
pNet_Send(ft->stream, req, strlen(domain)+6);
break;
}
}
}
}
}
*/
ot = XML_ChildOfTreeNS(tree, "http://jabber.org/protocol/ibb", "open", 0);
if (ot)
{
@ -2211,9 +2303,9 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree)
char *stanza = XML_GetParameter(ot, "stanza", "iq");
for (ft = jcl->ft; ft; ft = ft->next)
{
if (!strcmp(ft->sid, sid))
if (!strcmp(ft->sid, sid) && !strcmp(ft->with, from))
{
if (!ft->begun && ft->transmitting == false)
if (ft->allowed && !ft->begun && ft->transmitting == false)
{
if (blocksize > 65536 || strcmp(stanza, "iq"))
{ //blocksize: MUST NOT be greater than 65535
@ -2244,7 +2336,7 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree)
//if its okay...
JCL_AddClientMessagef(jcl, "<iq id='%s' to='%s' type='result'/>", id, from);
}
return;
break;
}
}
}
@ -2257,7 +2349,7 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree)
for (link = &jcl->ft; *link; link = &(*link)->next)
{
ft = *link;
if (!strcmp(ft->sid, sid))
if (!strcmp(ft->sid, sid) && !strcmp(ft->with, from))
{
if (ft->begun && ft->method == FT_IBB)
{
@ -2265,7 +2357,10 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree)
pFS_Close(ft->file);
if (ft->transmitting)
{
Con_Printf("%s aborted transfer of \"%s\"\n", from, ft->fname);
if (ft->eof)
Con_Printf("Sent \"%s\" to \"%s\"\n", ft->fname, ft->with);
else
Con_Printf("%s aborted transfer of \"%s\"\n", from, ft->fname);
}
else
{
@ -2329,47 +2424,35 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree)
char *md5hash = XML_GetParameter(file, "hash", "");
int fsize = strtoul(XML_GetParameter(file, "size", "0"), NULL, 0);
char *desc = XML_GetChildBody(file, "desc", "");
char authlink[512];
char denylink[512];
//file transfer offer
struct ft_s *ft = malloc(sizeof(*ft));
struct ft_s *ft = malloc(sizeof(*ft) + strlen(from)+1);
memset(ft, 0, sizeof(*ft));
ft->next = jcl->ft;
jcl->ft = ft;
ft->privateid = ++jcl->privateidseq;
ft->transmitting = false;
Q_strlcpy(ft->iqid, id, sizeof(ft->iqid));
Q_strlcpy(ft->sid, sid, sizeof(ft->sid));
Q_strlcpy(ft->fname, fname, sizeof(ft->sid));
Base64_Decode(ft->md5hash, sizeof(ft->md5hash), md5hash, strlen(md5hash));
ft->size = fsize;
ft->file = -1;
// ft->with =
ft->method = FT_IBB;
ft->with = (char*)(ft+1);
strcpy(ft->with, from);
ft->method = (fsize > 1024*128)?FT_BYTESTREAM:FT_IBB; //favour bytestreams for large files. for small files, just use ibb as it saves sorting out proxies.
ft->begun = false;
Con_Printf("Receiving file \"%s\" from \"%s\" (%i bytes)\n", fname, from, fsize);
//generate a response.
//FIXME: we ought to delay response until after we prompt.
repiq = XML_CreateNode(NULL, "iq", "", "");
XML_AddParameter(repiq, "type", "result");
XML_AddParameter(repiq, "to", from);
XML_AddParameter(repiq, "id", id);
repsi = XML_CreateNode(repiq, "si", "http://jabber.org/protocol/si", "");
XML_CreateNode(repsi, "file", "http://jabber.org/protocol/si/profile/file-transfer", ""); //I don't really get the point of this.
c = XML_CreateNode(repsi, "feature", "http://jabber.org/protocol/feature-neg", "");
c = XML_CreateNode(c, "x", "jabber:x:data", "");
XML_AddParameter(c, "type", "submit");
c = XML_CreateNode(c, "field", "", "");
XML_AddParameter(c, "var", "stream-method");
if (ft->method == FT_IBB)
c = XML_CreateNode(c, "value", "", "http://jabber.org/protocol/ibb");
else if (ft->method == FT_BYTESTREAM)
c = XML_CreateNode(c, "value", "", "http://jabber.org/protocol/bytestreams");
//FIXME: make bytestreams work.
ft->method = FT_IBB;
s = XML_GenerateString(repiq, false);
JCL_AddClientMessageString(jcl, s);
free(s);
XML_Destroy(repiq);
JCL_GenLink(jcl, authlink, sizeof(authlink), "fauth", from, NULL, va("%i", ft->privateid), "%s", "Accept");
JCL_GenLink(jcl, denylink, sizeof(denylink), "fdeny", from, NULL, va("%i", ft->privateid), "%s", "Deny");
Con_Printf("%s has offered to send you \"%s\" (%i bytes). %s %s\n", from, fname, fsize, authlink, denylink);
}
else
{
@ -2425,7 +2508,7 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree)
for (link = &jcl->pendingiqs; *link; link = &(*link)->next)
{
iq = *link;
if (!strcmp(iq->id, id) && !strcmp(iq->to, from))
if (!strcmp(iq->id, id) && (!strcmp(iq->to, from) || !*iq->to))
break;
}
if (*link)
@ -3150,6 +3233,7 @@ int JCL_ClientFrame(jclient_t *jcl)
char out[512];
char *method = NULL;
int outlen = -1;
qboolean needpass = false;
if (jcl->forcetls > 0 && !jcl->issecure)
{
if (BUILTINISVALID(Net_SetTLSClient))
@ -3174,18 +3258,23 @@ int JCL_ClientFrame(jclient_t *jcl)
if (!strcmp(m->body, method))
{
outlen = saslmethods[sm].sasl_initial(jcl, out, sizeof(out));
if (outlen != -1)
if (outlen >= 0)
break;
if (outlen == -2)
needpass = true;
}
}
if (outlen != -1)
if (outlen >= 0)
break;
}
if (outlen == -2)
if (outlen < 0)
{
XML_Destroy(tree);
return JCL_KILL;
//can't authenticate for some reason
if (needpass)
XMPP_Menu_Password(jcl);
return JCL_NUKEFROMORBIT;
}
if (outlen >= 0)
@ -3773,7 +3862,7 @@ void JCL_PrintBuddyList(char *console, jclient_t *jcl, qboolean all)
{
JCL_FindBuddy(jcl, ft->with, &b, &r);
JCL_GenLink(jcl, convolink, sizeof(convolink), NULL, b->accountdomain, r->resource, NULL, "%s", b->name);
JCL_GenLink(jcl, actlink, sizeof(actlink), "ftdeny", ft->with, NULL, ft->sid, "%s", "Hang Up");
JCL_GenLink(jcl, actlink, sizeof(actlink), "fdeny", ft->with, NULL, ft->sid, "%s", "Cancel");
Con_SubPrintf(console, " %s: %s\n", convolink, ft->fname);
}
#endif
@ -3860,7 +3949,7 @@ void JCL_AttentionMessage(jclient_t *jcl, char *to, char *msg)
}
}
void JCL_ToJID(jclient_t *jcl, char *in, char *out, int outsize)
void JCL_ToJID(jclient_t *jcl, char *in, char *out, int outsize, qboolean assumeresource)
{
//decompose links first
if (in[0] == '^' && in[1] == '[')
@ -3892,7 +3981,23 @@ void JCL_ToJID(jclient_t *jcl, char *in, char *out, int outsize)
{
if (!strcasecmp(b->name, in))
{
if (b->defaultresource)
if (b->defaultresource && assumeresource)
Q_snprintf(out, outsize, "%s/%s", b->accountdomain, b->defaultresource->resource);
else
Q_strlcpy(out, b->accountdomain, outsize);
return;
}
}
}
if (assumeresource)
{
buddy_t *b;
for (b = jcl->buddies; b; b = b->next)
{
if (!strcasecmp(b->accountdomain, in))
{
if (b->defaultresource && assumeresource)
Q_snprintf(out, outsize, "%s/%s", b->accountdomain, b->defaultresource->resource);
else
Q_strlcpy(out, b->accountdomain, outsize);
@ -3933,6 +4038,76 @@ void JCL_JoinMUCChat(jclient_t *jcl, char *room, char *server, char *myhandle, c
}
#ifdef FILETRANSFERS
void JCL_FT_AcceptFile(jclient_t *jcl, int fileid, qboolean accept)
{
struct ft_s *ft, **link;
char *s;
xmltree_t *repiq, *repsi, *c;
for (link = &jcl->ft; ft=*link; link = &(*link)->next)
{
if (ft->privateid == fileid)
break;
}
if (!ft)
{
Con_Printf("File not known\n");
return;
}
if (!accept)
{
Con_Printf("Declining file \"%s\" from \"%s\" (%i bytes)\n", ft->fname, ft->with, ft->size);
if (!ft->allowed)
{
JCL_AddClientMessagef(jcl,
"<iq type='error' to='%s' id='%s'>"
"<error type='cancel'>"
"<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
"<text>Offer Declined</text>"
"</error>"
"</iq>", ft->with, ft->iqid);
}
else
{
//FIXME: send a proper cancel
}
pFS_Close(ft->file);
*link = ft->next;
free(ft);
}
else
{
Con_Printf("Receiving file \"%s\" from \"%s\" (%i bytes)\n", ft->fname, ft->with, ft->size);
ft->allowed = true;
//generate a response.
//FIXME: we ought to delay response until after we prompt.
repiq = XML_CreateNode(NULL, "iq", "", "");
XML_AddParameter(repiq, "type", "result");
XML_AddParameter(repiq, "to", ft->with);
XML_AddParameter(repiq, "id", ft->iqid);
repsi = XML_CreateNode(repiq, "si", "http://jabber.org/protocol/si", "");
XML_CreateNode(repsi, "file", "http://jabber.org/protocol/si/profile/file-transfer", ""); //I don't really get the point of this.
c = XML_CreateNode(repsi, "feature", "http://jabber.org/protocol/feature-neg", "");
c = XML_CreateNode(c, "x", "jabber:x:data", "");
XML_AddParameter(c, "type", "submit");
c = XML_CreateNode(c, "field", "", "");
XML_AddParameter(c, "var", "stream-method");
if (ft->method == FT_IBB)
c = XML_CreateNode(c, "value", "", "http://jabber.org/protocol/ibb");
else if (ft->method == FT_BYTESTREAM)
c = XML_CreateNode(c, "value", "", "http://jabber.org/protocol/bytestreams");
s = XML_GenerateString(repiq, false);
JCL_AddClientMessageString(jcl, s);
free(s);
XML_Destroy(repiq);
}
}
qboolean JCL_FT_IBBChunked(jclient_t *jcl, xmltree_t *x, struct iq_s *iq)
{
char *from = XML_GetParameter(x, "from", "");
@ -3950,6 +4125,13 @@ qboolean JCL_FT_IBBChunked(jclient_t *jcl, xmltree_t *x, struct iq_s *iq)
Base64_Add(rawbuf, sz);
Base64_Finish();
if (sz > 0)
{
ft->sizedone += sz;
if (ft->sizedone == ft->size)
ft->eof = true;
}
if (sz && strlen(base64))
{
x = XML_CreateNode(NULL, "data", "http://jabber.org/protocol/ibb", base64);
@ -3978,7 +4160,7 @@ qboolean JCL_FT_IBBChunked(jclient_t *jcl, xmltree_t *x, struct iq_s *iq)
return true;
}
}
return false;
return true; //the ack can come after the bytestream has already finished sending. don't warn about that.
}
qboolean JCL_FT_IBBBegun(jclient_t *jcl, xmltree_t *x, struct iq_s *iq)
{
@ -4042,6 +4224,42 @@ qboolean JCL_FT_OfferAcked(jclient_t *jcl, xmltree_t *x, struct iq_s *iq)
}
#endif
void XMPP_Menu_Password(jclient_t *acc)
{
int y;
pCmd_AddText("conmenu\n"
"{\n"
"menuclear\n"
"if (option == \"SignIn\")\n"
"{\n"COMMANDPREFIX" /password ${0}\n}\n"
"}\n", false);
y = 36;
pCmd_AddText(va("menutext 48 %i \"^sXMPP Sign In\"\n", y), false); y+=16;
pCmd_AddText(va("menutext 48 %i \"^sPlease provide your password for\"\n", y), false); y+=16;
pCmd_AddText(va("menueditpriv 48 %i \"%s@%s\" \"example\"\n", y, acc->username, acc->domain), false);y+=16;
pCmd_AddText(va("menutext 48 %i \"Sign In\" SignIn\n", y), false);
pCmd_AddText(va("menutext 256 %i \"Cancel\" cancel\n", y), false);
}
void XMPP_Menu_Connect(void)
{
int y;
pCmd_AddText("conmenu\n"
"{\n"
"menuclear\n"
"if (option == \"SignIn\")\n"
"{\n"COMMANDPREFIX" /connect ${0}@${1}/${2}\n}\n"
"}\n", false);
y = 36;
pCmd_AddText(va("menutext 48 %i \"^sXMPP Sign In\"\n", y), false); y+=16;
pCmd_AddText(va("menueditpriv 48 %i \"Username\" \"example\"\n", y), false);y+=16;
pCmd_AddText(va("menueditpriv 48 %i \"Domain\" \"gmail.com\"\n", y), false);y+=16;
pCmd_AddText(va("menueditpriv 48 %i \"Resource\" \"\"\n", y), false);y+=32;
pCmd_AddText(va("menutext 48 %i \"Sign In\" SignIn\n", y), false);
pCmd_AddText(va("menutext 256 %i \"Cancel\" cancel\n", y), false);
}
void JCL_Command(int accid, char *console)
{
char imsg[8192];
@ -4061,8 +4279,9 @@ void JCL_Command(int accid, char *console)
for (i = 0; i < 6; i++)
{
if (!msg)
continue;
msg = JCL_ParseOut(msg, arg[i], sizeof(arg[i]));
*arg[i] = 0;
else
msg = JCL_ParseOut(msg, arg[i], sizeof(arg[i]));
}
if (arg[0][0] == '/' && arg[0][1] != '/' && strcmp(arg[0]+1, "me"))
@ -4072,6 +4291,7 @@ void JCL_Command(int accid, char *console)
int tls;
if (!*arg[1])
{
XMPP_Menu_Connect();
Con_SubPrintf(console, "%s <account@domain/resource> <password> <server>\n", arg[0]+1);
return;
}
@ -4163,6 +4383,12 @@ void JCL_Command(int accid, char *console)
if (jcl->status == JCL_INACTIVE)
jcl->status = JCL_DEAD;
}
else if (!strcmp(arg[0]+1, "password"))
{
Q_strncpyz(jcl->password, arg[1], sizeof(jcl->password));
if (jcl->status == JCL_INACTIVE)
jcl->status = JCL_DEAD;
}
else if (!strcmp(arg[0]+1, "quit"))
{
//disconnect from the xmpp server.
@ -4215,27 +4441,22 @@ void JCL_Command(int accid, char *console)
#ifdef JINGLE
else if (!strcmp(arg[0]+1, "join"))
{
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname));
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname), true);
JCL_Join(jcl, nname, NULL, true, ICEP_QWCLIENT);
}
else if (!strcmp(arg[0]+1, "invite"))
{
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname));
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname), true);
JCL_Join(jcl, nname, NULL, true, ICEP_QWSERVER);
}
else if (!strcmp(arg[0]+1, "voice") || !strcmp(arg[0]+1, "call"))
{
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname));
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname), true);
JCL_Join(jcl, nname, NULL, true, ICEP_VOICE);
}
else if (!strcmp(arg[0]+1, "kick"))
{
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname));
JCL_Join(jcl, nname, NULL, false, ICEP_INVALID);
}
else if (!strcmp(arg[0]+1, "kick"))
{
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname));
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname), true);
JCL_Join(jcl, nname, NULL, false, ICEP_INVALID);
}
#endif
@ -4254,7 +4475,7 @@ void JCL_Command(int accid, char *console)
}
else
{
JCL_ToJID(jcl, *arg[2]?arg[2]:console, nname, sizeof(nname));
JCL_ToJID(jcl, *arg[2]?arg[2]:console, nname, sizeof(nname), true);
Con_SubPrintf(console, "Offering %s to %s.\n", fname, nname);
@ -4262,7 +4483,7 @@ void JCL_Command(int accid, char *console)
memset(ft, 0, sizeof(*ft));
ft->next = jcl->ft;
jcl->ft = ft;
ft->allowed = true;
ft->transmitting = true;
ft->blocksize = 4096;
Q_strlcpy(ft->fname, fname, sizeof(ft->fname));
@ -4275,20 +4496,20 @@ void JCL_Command(int accid, char *console)
//generate an offer.
xsi = XML_CreateNode(NULL, "si", "http://jabber.org/protocol/si", "");
XML_AddParameter(xsi, "profile", "http://jabber.org/protocol/si/profile/file-transfer");
XML_AddParameter(xsi, "id", ft->sid);
XML_AddParameter(xsi, "profile", "http://jabber.org/protocol/si/profile/file-transfer");
XML_AddParameter(xsi, "id", ft->sid);
//XML_AddParameter(xsi, "mime-type", "text/plain");
xfile = XML_CreateNode(xsi, "file", "http://jabber.org/protocol/si/profile/file-transfer", ""); //I don't really get the point of this.
XML_AddParameter(xfile, "name", ft->fname);
XML_AddParameteri(xfile, "size", ft->size);
XML_AddParameter(xfile, "name", ft->fname);
XML_AddParameteri(xfile, "size", ft->size);
c = XML_CreateNode(xsi, "feature", "http://jabber.org/protocol/feature-neg", "");
c = XML_CreateNode(c, "x", "jabber:x:data", "");
XML_AddParameter(c, "type", "form");
c = XML_CreateNode(c, "field", "", "");
XML_AddParameter(c, "var", "stream-method");
XML_AddParameter(c, "type", "listsingle");
XML_CreateNode(XML_CreateNode(c, "option", "", ""), "value", "", "http://jabber.org/protocol/ibb");
// XML_CreateNode(XML_CreateNode(c, "option", "", ""), "value", "", "http://jabber.org/protocol/bytestreams");
c = XML_CreateNode(c, "x", "jabber:x:data", "");
XML_AddParameter(c, "type", "form");
c = XML_CreateNode(c, "field", "", "");
XML_AddParameter(c, "var", "stream-method");
XML_AddParameter(c, "type", "listsingle");
XML_CreateNode(XML_CreateNode(c, "option", "", ""), "value", "", "http://jabber.org/protocol/ibb");
// XML_CreateNode(XML_CreateNode(c, "option", "", ""), "value", "", "http://jabber.org/protocol/bytestreams");
JCL_SendIQNode(jcl, JCL_FT_OfferAcked, "set", nname, xsi, true)->usrptr = ft;
}
@ -4325,12 +4546,12 @@ void JCL_Command(int accid, char *console)
"/me goes to order cod and chips. brb",
"/me goes to watch some monty python"
};
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname));
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname), true);
JCL_AttentionMessage(jcl, nname, msgtab[rand()%(sizeof(msgtab)/sizeof(msgtab[0]))]);
}
else if (!strcmp(arg[0]+1, "poke"))
{
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname));
JCL_ToJID(jcl, *arg[1]?arg[1]:console, nname, sizeof(nname), true);
JCL_AttentionMessage(jcl, nname, NULL);
}
else if (!strcmp(arg[0]+1, "raw"))
@ -4374,7 +4595,7 @@ void JCL_Command(int accid, char *console)
}
else
{
JCL_ToJID(jcl, *console?console:jcl->defaultdest, nname, sizeof(nname));
JCL_ToJID(jcl, *console?console:jcl->defaultdest, nname, sizeof(nname), true);
JCL_SendMessage(jcl, nname, msg);
}
}

View File

@ -875,6 +875,9 @@ static qboolean JCL_JingleHandleSessionTerminate(jclient_t *jcl, xmltree_t *tree
}
static qboolean JCL_JingleHandleSessionAccept(jclient_t *jcl, xmltree_t *tree, char *from, struct c2c_s *c2c, buddy_t *b)
{
//peer accepted our session
//make sure it actually was ours, and not theirs. sneaky sneaky.
//will generally contain some port info.
if (!c2c)
{
Con_DPrintf("Unknown session acceptance\n");
@ -972,6 +975,51 @@ qboolean JCL_HandleGoogleSession(jclient_t *jcl, xmltree_t *tree, char *from, ch
return true;
}
#endif
enum
{
JE_ACKNOWLEDGE,
JE_UNSUPPORTED,
JE_OUTOFORDER,
JE_TIEBREAK,
JE_UNKNOWNSESSION,
JE_UNSUPPORTEDINFO
};
void JCL_JingleError(jclient_t *jcl, xmltree_t *tree, char *from, char *id, int type)
{
switch(type)
{
case JE_ACKNOWLEDGE:
JCL_AddClientMessagef(jcl,
"<iq type='result' to='%s' id='%s' />", from, id);
break;
case JE_UNSUPPORTED:
JCL_AddClientMessagef(jcl,
"<iq id='%s' to='%s' type='error'>"
"<error type='cancel'>"
"<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
"</error>"
"</iq>", id, from);
break;
case JE_UNKNOWNSESSION:
JCL_AddClientMessagef(jcl,
"<iq id='%s' to='%s' type='error'>"
"<error type='modify'>"
"<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
"<unknown-session xmlns='urn:xmpp:jingle:errors:1'/>"
"</error>"
"</iq>", id, from);
break;
case JE_UNSUPPORTEDINFO:
JCL_AddClientMessagef(jcl,
"<iq id='%s' to='%s' type='error'>"
"<error type='modify'>"
"<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
"<unsupported-info xmlns='urn:xmpp:jingle:errors:1'/>"
"</error>"
"</iq>", id, from);
break;
}
}
qboolean JCL_ParseJingle(jclient_t *jcl, xmltree_t *tree, char *from, char *id)
{
char *action = XML_GetParameter(tree, "action", "");
@ -1002,22 +1050,85 @@ qboolean JCL_ParseJingle(jclient_t *jcl, xmltree_t *tree, char *from, char *id)
//FIXME: transport-info, transport-replace
if (!strcmp(action, "session-terminate"))
{
JCL_JingleHandleSessionTerminate(jcl, tree, c2c, link, b);
if (c2c)
{
JCL_JingleError(jcl, tree, from, id, JE_ACKNOWLEDGE);
JCL_JingleHandleSessionTerminate(jcl, tree, c2c, link, b);
}
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
//content-accept
//content-add
//content-modify
//content-reject
//content-remove
//description-info
//security-info
//
else if (!strcmp(action, "content-accept"))
{
//response from content-add
if (c2c)
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTED);
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
else if (!strcmp(action, "content-add"))
{
//FIXME: must send content-reject
if (c2c)
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTED);
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
else if (!strcmp(action, "content-modify"))
{
//send an error to reject it
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTED);
}
else if (!strcmp(action, "content-reject"))
{
//response from content-add. an error until we actually generate content-adds...
if (c2c)
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTED);
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
else if (!strcmp(action, "content-remove"))
{
if (c2c)
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTED);
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
else if (!strcmp(action, "description-info"))
{
//The description-info action is used to send informational hints about parameters related to the application type, such as the suggested height and width of a video display area or suggested configuration for an audio stream.
//just ack and ignore it
if (c2c)
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTED);
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
else if (!strcmp(action, "security-info"))
{
//The security-info action is used to send information related to establishment or maintenance of security preconditions.
//no security mechanisms supported...
if (c2c)
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTED);
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
else if (!strcmp(action, "session-info"))
{
if (tree->child)
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTEDINFO);
else
JCL_JingleError(jcl, tree, from, id, JE_ACKNOWLEDGE); //serves as a ping.
}
else if (!strcmp(action, "transport-info"))
{ //peer wants to add ports.
if (c2c)
{
JCL_JingleError(jcl, tree, from, id, JE_ACKNOWLEDGE);
JCL_JingleParsePeerPorts(jcl, c2c, tree, from, sid);
}
else
Con_DPrintf("Received transport-info without an active session\n");
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
//FIXME: we need to add support for this to downgrade to raw if someone tries calling through a SIP gateway
else if (!strcmp(action, "transport-replace"))
@ -1025,39 +1136,51 @@ qboolean JCL_ParseJingle(jclient_t *jcl, xmltree_t *tree, char *from, char *id)
if (c2c)
{
if (1)
{
JCL_JingleError(jcl, tree, from, id, JE_ACKNOWLEDGE);
JCL_JingleSend(jcl, c2c, "transport-reject");
}
else
{
JCL_JingleError(jcl, tree, from, id, JE_ACKNOWLEDGE);
JCL_JingleParsePeerPorts(jcl, c2c, tree, from, sid);
JCL_JingleSend(jcl, c2c, "transport-accept");
}
}
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
else if (!strcmp(action, "transport-reject"))
{
JCL_JingleError(jcl, tree, from, id, JE_ACKNOWLEDGE);
JCL_JingleSend(jcl, c2c, "session-terminate");
}
else if (!strcmp(action, "session-accept"))
{
if (!JCL_JingleHandleSessionAccept(jcl, tree, from, c2c, b))
return false;
if (c2c)
{
//response from a message we sent.
if (JCL_JingleHandleSessionAccept(jcl, tree, from, c2c, b))
JCL_JingleError(jcl, tree, from, id, JE_ACKNOWLEDGE);
else
JCL_JingleError(jcl, tree, from, id, JE_OUTOFORDER);
}
else
JCL_JingleError(jcl, tree, from, id, JE_UNKNOWNSESSION);
}
else if (!strcmp(action, "session-initiate"))
{
// Con_Printf("Peer initiating connection!\n");
// XML_ConPrintTree(tree, 0);
if (!JCL_JingleHandleInitiate(jcl, tree, from))
return false;
JCL_JingleError(jcl, tree, from, id, JE_ACKNOWLEDGE);
JCL_JingleHandleInitiate(jcl, tree, from);
}
else
{
Con_Printf("Unknown jingle action: %s\n", action);
// XML_ConPrintTree(tree, 0);
JCL_JingleError(jcl, tree, from, id, JE_UNSUPPORTED);
}
JCL_AddClientMessagef(jcl,
"<iq type='result' to='%s' id='%s' />", from, id);
return true;
}
#endif

View File

@ -190,14 +190,20 @@ typedef struct jclient_s
struct ft_s *next;
char fname[MAX_QPATH];
int size;
int sizedone;
char *with;
char md5hash[16];
int privateid;
char iqid[64];
char sid[64];
int blocksize;
unsigned short seq;
qhandle_t file;
qboolean begun;
qboolean transmitting;
qhandle_t stream;
qboolean begun; //handshake
qboolean eof;
qboolean transmitting; //we're offering
qboolean allowed; //if false, don't handshake the transfer
enum
{
@ -205,6 +211,7 @@ typedef struct jclient_s
FT_BYTESTREAM //aka: relay
} method;
} *ft;
int privateidseq;
#endif
buddy_t *buddies;
@ -232,4 +239,6 @@ void JCL_Join(jclient_t *jcl, char *target, char *sid, qboolean allow, int proto
void JCL_JingleTimeouts(jclient_t *jcl, qboolean killall);
//jingle iq message handlers
qboolean JCL_HandleGoogleSession(jclient_t *jcl, xmltree_t *tree, char *from, char *id);
qboolean JCL_ParseJingle(jclient_t *jcl, xmltree_t *tree, char *from, char *id);
qboolean JCL_ParseJingle(jclient_t *jcl, xmltree_t *tree, char *from, char *id);
void JCL_FT_AcceptFile(jclient_t *jcl, int fileid, qboolean accept);

View File

@ -390,6 +390,9 @@ void MPQ_BuildHash(searchpathfuncs_t *handle, int depth, void (QDECL *AddFileHas
while (*n && *n != '\r' && *n != '\n' && *n != ';')
n++;
if (n-s >= sizeof(name))
continue;
memcpy(name, s, n - s);
name[n-s] = 0;
//precompute the name->block lookup. fte normally does the hashing outside the archive code.

View File

@ -10,6 +10,9 @@
<Platform
Name="Win32"
/>
<Platform
Name="x64"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
@ -169,6 +172,163 @@
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../engine/server;../../engine/gl;../../engine/qclib;../../engine/client;../../engine/common"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;FTEPLUGIN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="zlib64.lib"
OutputFile="../../fteplug_mpqamd64.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="../..\engine\libs"
ModuleDefinitionFile="../plugin.def"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|x64"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../engine/server;../../engine/gl;../../engine/qclib;../../engine/client;../../engine/common"
PreprocessorDefinitions="WIN32;FTEPLUGIN"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="zlib.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="../..\engine\libs"
ModuleDefinitionFile="../plugin.def"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>