Reworked client support for DPP5+. less code now, its much more graceful.

added waterfog command. waterfog overrides regular fog only when the view is in water.
fixed 64bit printf format specifiers. should work better on winxp64.
fixed some spec angle weirdness.
fixed viewsize 99.99 weirdness with ezhud.
fixed extra offset on the console (exhibited in 64bit builds, but not limited to).
fixed .avi playback, can now actually display frames again.
reimplemented line sparks.
fixed r_editlights_save flipping the light's pitch.
fixed issue with oggs failing to load.
fixed condump to cope with unicode properly.
made sv_bigcoords default except in quake. hexen2 kinda needs it for bsp angle precision.
fixed nq server to not stall weirdly on map changes.
fixed qwprogs svc_cdtrack not bugging out with nq clients on the server.
fixed restart command to load the last map run by the server, instead of start.bsp (when idle)
optimised d3d9 renderer a little. now uses less draw calls, especially with complex scenes. seems to get higher framerates than opengl now.
fixed d3d9 renderer to not bug out quite so much when run fullscreen (shader subsystem is now correctly initialised).
fixed a couple of bugs from font change. also now supports utf-8 in a few more places.
r_editlights_reload no longer generates rtlights inside the void. this resolves a few glitches (but should also help framerates a little).
fixed so corona-only lights won't generate shadowmaps and waste lots of time.
removed lots of #defines from qclib. I should never have made them in the first place, but I was lazy. obviously there's more left that I cba to remove yet.
fixed nested calls with variant-vectors. this fixes csaddon's light editor.
fixed qcc hc calling conventions using redundant stores.
disabled keywords can still be used by using __keyword instead.
fixed ftegccgui grep feature.
fixed motionless-dog qcc bug.
tweaked qcc warnings a little. -Wall is now a viable setting. you should be able to fix all those warnings.
fixed qw svc_intermission + dpp5+ clients bug.
fixed annoying spam about disconnecting in hexen2.
rewrote status command a little to cope with ipv6 addresses more gracefully
fixed significant stall when hibernating/debugging a server with a player sitting on it.
fixed truelightning.
fixed rocketlight overriding pflags.
fixed torches vanishing on vid_restart.
fixed issue with decal scaling.
fixed findentityfield builtin.
fixed fteqcc issue with ptr+1
fixed use of arrays inside class functions.
fixed/implemented fteqcc emulation of pointer opcodes.
added __inout keyword to fteqcc, so that it doesn't feel so horrendous.
fixed sizeof(*foo)
fixed *struct = struct;
fixed recursive structs.
fixed fteqcc warning report.
fixed sdl2 controller support, hopefully.
attempted to implement xinput, including per-player audio playback.
slightly fixed relaxed attitude to mouse focus when running fullscreen.
fixed weird warnings/errors with 'ent.arrayhead' terms. now generates sane errors.
implemented bindmaps (for csqc).
fixed crashing bug with eprint builtin.
implemented subset of music_playlist_* functionality. significant changes to music playback.
fixed some more dpcsqc compat.
fixed binds menu. now displays and accepts modifiers.
fixed issues with huge lightmaps.
fixed protocol determinism with dp clients connecting to fte servers. the initial getchallenge request now inhibits vanilla nq connection requests.
implemented support for 'dupe' userinfo key, allowing clients to request client->server packet duplication. should probably queue them tbh.
implemented sv_saveentfile command.
fixed resume after breaking inside a stepped-over function.
fixed erroneous footer after debugging.
(I wonder just how many things I broke with these fixes)

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4946 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-07-26 10:56:18 +00:00
parent 9ecc276ce3
commit 6d36834f8e
114 changed files with 4049 additions and 2054 deletions

View File

@ -934,10 +934,10 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
break;
case CG_S_STARTBACKGROUNDTRACK:
Media_BackgroundTrack(VM_POINTER(arg[0]), VM_POINTER(arg[1]));
Media_NamedTrack(VM_POINTER(arg[0]), VM_POINTER(arg[1]));
return 0;
case CG_S_STOPBACKGROUNDTRACK:
Media_BackgroundTrack(NULL, NULL);
Media_NamedTrack(NULL, NULL);
return 0;
case CG_S_CLEARLOOPINGSOUNDS:
//clearall
@ -954,13 +954,13 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
vec3_t *axis = VM_POINTER(arg[2]);
int inwater = VM_LONG(arg[3]);
r_refdef.audio.defaulted = false;
cl.playerview[0].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;
VectorCopy(org, cl.playerview[0].audio.origin);
VectorCopy(axis[0], cl.playerview[0].audio.forward);
VectorCopy(axis[1], cl.playerview[0].audio.right);
VectorCopy(axis[2], cl.playerview[0].audio.up);
cl.playerview[0].audio.inwater = inwater;
}
break;
@ -976,8 +976,8 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
case CG_KEY_GETKEY:
{
int ret[2];
M_FindKeysForCommand (0, VM_POINTER(arg[0]), ret);
int ret[1];
M_FindKeysForCommand (0, 0, VM_POINTER(arg[0]), ret, NULL, countof(ret));
return ret[0];
}
break;

View File

@ -562,7 +562,7 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *
if ((bits & (UF_EFFECTS | UF_EFFECTS2)) == (UF_EFFECTS | UF_EFFECTS2))
news->effects = MSG_ReadLong();
else if (bits & UF_EFFECTS2)
news->effects = MSG_ReadShort();
news->effects = (unsigned short)MSG_ReadShort();
else if (bits & UF_EFFECTS)
news->effects = MSG_ReadByte();
@ -639,9 +639,12 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *
if (!(predbits & UFP_VIEWANGLE) || !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{
news->u.q1.vangle[0] = ANGLE2SHORT(news->angles[0]);
news->u.q1.vangle[1] = ANGLE2SHORT(news->angles[1]);
news->u.q1.vangle[2] = ANGLE2SHORT(news->angles[2]);
if (bits & UF_ANGLESXZ)
news->u.q1.vangle[0] = ANGLE2SHORT(news->angles[0] * ((bits & UF_PREDINFO)?-3:-1));
if (bits & UF_ANGLESY)
news->u.q1.vangle[1] = ANGLE2SHORT(news->angles[1]);
if (bits & UF_ANGLESXZ)
news->u.q1.vangle[2] = ANGLE2SHORT(news->angles[2]);
}
if (bits & UF_MODEL)
@ -1202,6 +1205,10 @@ entity_state_t *CL_FindOldPacketEntity(int num)
void DP5_ParseDelta(entity_state_t *s)
{
int bits;
if (cl_shownet.ival >= 3)
Con_Printf("%3i: Update %i", msg_readcount, s->number);
bits = MSG_ReadByte();
if (bits & E5_EXTEND1)
{
@ -1214,6 +1221,43 @@ void DP5_ParseDelta(entity_state_t *s)
}
}
if (cl_shownet.ival >= 3)
{
if (bits & E5_FULLUPDATE) Con_Printf(" full");
if (bits & E5_ORIGIN) Con_Printf(" origin");
if (bits & E5_ANGLES) Con_Printf(" angles");
if (bits & E5_MODEL) Con_Printf(" model");
if (bits & E5_FRAME) Con_Printf(" frame");
if (bits & E5_SKIN) Con_Printf(" kin");
if (bits & E5_EFFECTS) Con_Printf(" effects");
if (bits & E5_EXTEND1) Con_Printf(" extend1");
if (bits & E5_FLAGS) Con_Printf(" flags");
if (bits & E5_ALPHA) Con_Printf(" alpha");
if (bits & E5_SCALE) Con_Printf(" scale");
if (bits & E5_ORIGIN32) Con_Printf(" origin32");
if (bits & E5_ANGLES16) Con_Printf(" angles16");
if (bits & E5_MODEL16) Con_Printf(" model16");
if (bits & E5_COLORMAP) Con_Printf(" colormap");
if (bits & E5_EXTEND2) Con_Printf(" extend2");
if (bits & E5_ATTACHMENT) Con_Printf(" attachment");
if (bits & E5_LIGHT) Con_Printf(" light");
if (bits & E5_GLOW) Con_Printf(" glow");
if (bits & E5_EFFECTS16) Con_Printf(" effects16");
if (bits & E5_EFFECTS32) Con_Printf(" effects32");
if (bits & E5_FRAME16) Con_Printf(" frame16");
if (bits & E5_COLORMOD) Con_Printf(" colormod");
if (bits & E5_EXTEND3) Con_Printf(" extend3");
if (bits & E5_GLOWMOD) Con_Printf(" glowmod");
if (bits & E5_COMPLEXANIMATION) Con_Printf(" complexanimation");
if (bits & E5_TRAILEFFECTNUM) Con_Printf(" traileffectnum");
if (bits & E5_UNUSED27) Con_Printf(" unused27");
if (bits & E5_UNUSED28) Con_Printf(" unused28");
if (bits & E5_UNUSED29) Con_Printf(" unused29");
if (bits & E5_UNUSED30) Con_Printf(" unused30");
if (bits & E5_EXTEND4) Con_Printf(" extend4");
Con_Printf("\n");
}
if (bits & E5_ALLUNUSED)
{
Host_EndGame("Detected 'unused' bits in DP5+ entity delta - %x (%x)\n", bits, (bits & E5_ALLUNUSED));
@ -1329,6 +1373,17 @@ void DP5_ParseDelta(entity_state_t *s)
s->u.q1.traileffectnum = MSG_ReadShort();
}
static int QDECL CLDP_SortEntities(const void *va, const void *vb)
{
const entity_state_t *a = va, *b = vb;
if (a->inactiveflag && b->inactiveflag)
return 0;
if ((a->number < b->number || b->inactiveflag) && !a->inactiveflag)
return -1;
else
return 1;
}
void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o(
{
//the incoming entities do not come in in any order. :(
@ -1339,12 +1394,11 @@ void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o(
//this gets in the way of tracking multiple frames, and thus doesn't match fte too well
packet_entities_t *pack, oldpack;
static packet_entities_t newpack;
packet_entities_t *oldpack, *newpack;
entity_state_t *to, *from;
unsigned int read;
int oldi, newi, lowesti, lowestv, newremaining;
int oldi;
qboolean remove;
//server->client sequence
@ -1356,14 +1410,31 @@ void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o(
if (cls.protocol_nq >= CPNQ_DP7)
CL_AckedInputFrame(cls.netchan.incoming_sequence, MSG_ReadLong(), true); /*client input sequence which has been acked*/
if (cl.validsequence)
oldpack = &cl.inframes[(cl.validsequence)&UPDATE_MASK].packet_entities;
else
oldpack = NULL;
cl.validsequence = cls.netchan.incoming_sequence;
cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].receivedtime = realtime;
cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].frameid = cls.netchan.incoming_sequence;
pack = &cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].packet_entities;
pack->servertime = cl.gametime;
oldpack = *pack;
oldi = 0;
newpack = &cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].packet_entities;
newpack->servertime = cl.gametime;
//copy old state to new state
if (newpack != oldpack)
{
if (oldpack)
{
newpack->num_entities = oldpack->num_entities;
newpack->max_entities = newpack->num_entities+16; //for slop for new ents, to reduce reallocs
newpack->entities = BZ_Realloc(newpack->entities, sizeof(entity_state_t)*newpack->max_entities);
memcpy(newpack->entities, oldpack->entities, sizeof(entity_state_t)*newpack->num_entities);
}
else
newpack->num_entities = 0;
}
oldpack = NULL;
newpack.num_entities = 0;
for (;;)
{
read = MSG_ReadShort();
@ -1378,98 +1449,57 @@ void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o(
Host_EndGame("Too many entities.\n");
from = &nullentitystate;
to = NULL;
for (oldi=0 ; oldi<oldpack.num_entities ; oldi++)
for (oldi=0 ; oldi<newpack->num_entities ; oldi++)
{
if (read == oldpack.entities[oldi].number)
if (read == newpack->entities[oldi].number)
{
from = &oldpack.entities[oldi];
from->inactiveflag |= 1; //so we don't copy it.
from = &newpack->entities[oldi];
to = &newpack->entities[oldi];
break;
}
}
if (remove)
{
continue;
}
if (!to)
{ //okay, so this is new
if (newpack->num_entities==newpack->max_entities)
{
newpack->max_entities = newpack->num_entities+16;
newpack->entities = BZ_Realloc(newpack->entities, sizeof(entity_state_t)*newpack->max_entities);
}
if (newpack.num_entities==newpack.max_entities)
{
newpack.max_entities = newpack.num_entities+16;
newpack.entities = BZ_Realloc(newpack.entities, sizeof(entity_state_t)*newpack.max_entities);
to = &newpack->entities[newpack->num_entities];
newpack->num_entities++;
}
to = &newpack.entities[newpack.num_entities];
newpack.num_entities++;
memcpy(to, from, sizeof(*to));
to->number = read;
DP5_ParseDelta(to);
to->inactiveflag &= ~1;
}
/*we're writing into the old one, clear it out prematurely (to make the malloc below trigger, and free it at the end)*/
pack->max_entities = 0;
pack->entities = NULL;
//make sure there's enough space for both lists
if (oldpack.num_entities + newpack.num_entities>=pack->max_entities)
{
pack->max_entities = oldpack.num_entities + newpack.num_entities;
pack->entities = BZ_Realloc(pack->entities, sizeof(entity_state_t)*pack->max_entities);
}
pack->num_entities = 0;
//we're read all the new states, so have current info
//merge the packets, sorting the new ones (so the output is always sorted)
for (oldi = 0, lowesti=0, lowestv = 0, newremaining = newpack.num_entities; newremaining || oldi < oldpack.num_entities; )
{
if (oldi == oldpack.num_entities)
from = NULL;
else
{
from = &oldpack.entities[oldi];
if (from->inactiveflag & 1)
{
oldi++;
continue;
}
}
if (newremaining && !lowestv)
{
lowestv = 0x7ffffffe;
for(newi = 0; newi < newpack.num_entities; newi++)
{
if (newpack.entities[newi].inactiveflag & 1)
continue;
if (newpack.entities[newi].number < lowestv)
{
lowestv = newpack.entities[newi].number;
lowesti = newi;
}
}
}
/*use the new packet instead if we need to*/
if (!from || (from->number > lowestv && lowestv))
{
from = &newpack.entities[lowesti];
from->inactiveflag |= 1;
lowestv = 0; /*find the next oldest*/
newremaining--;
if (remove)
{ //ent is meant to be removed. flag it as such. we'll strip it out later.
if (cl_shownet.ival >= 3)
Con_Printf("Remove %i\n", read);
to->inactiveflag = 1;
}
else
oldi++;
to = &pack->entities[pack->num_entities];
pack->num_entities++;
memcpy(to, from, sizeof(*to));
to->inactiveflag &= ~1;
{
// Con_Printf("Update %i\n", read);
DP5_ParseDelta(to);
to->inactiveflag = 0;
}
}
BZ_Free(oldpack.entities);
qsort(newpack->entities, newpack->num_entities, sizeof(entity_state_t), CLDP_SortEntities);
//get rid of any removed ents (we sorted these to the end)
while (newpack->num_entities)
{
if (newpack->entities[newpack->num_entities-1].inactiveflag)
newpack->num_entities--;
else
break;
}
}
void CLNQ_ParseEntity(unsigned int bits)
@ -2659,6 +2689,70 @@ void CL_AddDecal(shader_t *shader, vec3_t origin, vec3_t up, vec3_t side, vec3_t
cl_numstris--;
}
void R_AddItemTimer(vec3_t shadoworg, float yaw, float radius, float percent)
{
vec3_t eang;
shader_t *s;
scenetris_t *t;
cl_adddecal_ctx_t ctx;
// if (!r_shadows.value)
// return;
s = R_RegisterShader("timershader", SUF_NONE,
"{\n"
"polygonoffset\n"
"program itemtimer\n"
"{\n"
"map $diffuse\n"
"blendfunc src_alpha one\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"}\n"
"}\n");
if (!s->prog)
return;
TEXASSIGN(s->defaulttextures->base, balltexture);
eang[0] = 0;
eang[1] = yaw;
eang[2] = 0;
AngleVectors(eang, ctx.axis[1], ctx.axis[2], ctx.axis[0]);
VectorNegate(ctx.axis[0], ctx.axis[0]);
ctx.offset[2] = DotProduct(shadoworg, ctx.axis[2]) + 0.5*radius;
ctx.offset[1] = DotProduct(shadoworg, ctx.axis[1]) + 0.5*radius;
ctx.offset[0] = DotProduct(shadoworg, ctx.axis[0]);
ctx.scale[1] = 1/radius;
ctx.scale[2] = 1/radius;
ctx.scale[0] = 0;//.5/radius;
/*reuse the previous trigroup if its the same shader*/
if (cl_numstris && cl_stris[cl_numstris-1].shader == s && cl_stris[cl_numstris-1].flags == (BEF_NODLIGHT|BEF_NOSHADOWS))
t = &cl_stris[cl_numstris-1];
else
{
if (cl_numstris == cl_maxstris)
{
cl_maxstris += 8;
cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris);
}
t = &cl_stris[cl_numstris++];
t->shader = s;
t->flags = BEF_NODLIGHT|BEF_NOSHADOWS;
t->numidx = 0;
t->numvert = 0;
t->firstidx = cl_numstrisidx;
t->firstvert = cl_numstrisvert;
}
ctx.t = t;
Vector4Set(ctx.rgbavalue, 0.1, 0.1, 0.1, percent);
Mod_ClipDecal(cl.worldmodel, shadoworg, ctx.axis[0], ctx.axis[1], ctx.axis[2], radius, CL_AddDecal_Callback, &ctx);
if (!t->numidx)
cl_numstris--;
}
void CLQ1_AddShadow(entity_t *ent)
{
float radius;
@ -2738,7 +2832,7 @@ void CLQ1_AddShadow(entity_t *ent)
void CLQ1_AddPowerupShell(entity_t *ent, qboolean viewweap, unsigned int effects)
{
entity_t *shell;
if (!(effects & (EF_BLUE | EF_RED)) || !v_powerupshell.value || !ent)
if (!(effects & (EF_BLUE | EF_RED | EF_GREEN)) || !v_powerupshell.value || !ent)
return;
if (cl_numvisedicts == cl_maxvisedicts)
@ -3359,7 +3453,7 @@ void CL_LinkPacketEntities (void)
//bots or powerup glows. items always glow, bots can be disabled
if (state->modelindex != cl_playerindex || r_powerupglow.ival)
if (state->effects & (EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT))
if (state->effects & (EF_GREEN | EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT))
{
vec3_t colour;
float radius;
@ -3396,6 +3490,13 @@ void CL_LinkPacketEntities (void)
colour[1] += 0.5;
colour[2] += 0.5;
}
if (state->effects & EF_GREEN)
{
radius = max(radius,200);
colour[0] += 0.5;
colour[1] += 3.0;
colour[2] += 0.5;
}
if (radius)
{
@ -3657,7 +3758,7 @@ void CL_LinkPacketEntities (void)
P_EmitEffect (ent->origin, model->particleeffect, &(le->emitstate));
//dlights are not so customisable.
if (r_rocketlight.value && (modelflags & MF_ROCKET))
if (r_rocketlight.value && (modelflags & MF_ROCKET) && !(state->lightpflags & (PFLAGS_FULLDYNAMIC|PFLAGS_CORONA)))
{
float rad = 0;
vec3_t dclr;

View File

@ -66,7 +66,7 @@ int Player_StringtoSlot(char *arg)
return ((slot = Player_IdtoSlot(Q_atoi(arg))) >= 0) ? slot : PLAYER_ID_NOMATCH;
}
int Player_NametoSlot(char *name)
int Player_NametoSlot(const char *name)
{
int i;
@ -95,17 +95,18 @@ char *Player_MyName (void)
cvar_t ignore_spec = SCVAR("ignore_spec", "0");
cvar_t ignore_qizmo_spec = SCVAR("ignore_qizmo_spec", "0");
cvar_t ignore_mode = SCVAR("ignore_mode", "0");
cvar_t ignore_flood_duration = SCVAR("ignore_flood_duration", "4");
cvar_t ignore_flood = SCVAR("ignore_flood", "0");
cvar_t ignore_opponents = SCVAR("ignore_opponents", "0");
cvar_t ignore_spec = CVAR("ignore_spec", "0");
cvar_t ignore_qizmo_spec = CVAR("ignore_qizmo_spec", "0");
cvar_t ignore_mode = CVAR("ignore_mode", "0");
cvar_t ignore_flood_duration = CVARD("ignore_flood_duration", "4", "Time limit for inbound messages to be considered duplicates.");
cvar_t ignore_flood = CVARD("ignore_flood", "0", "Provides a way to reduce inbound spam from flooding out your chat (dupe messages are ignored).\n0: No inbound flood protection.\n1: Duplicate non-team messages will be filtered.\n2: ALL duplicate messages will be filtered\n");
cvar_t ignore_opponents = CVAR("ignore_opponents", "0");
char ignoreteamlist[MAX_TEAMIGNORELIST][16 + 1];
typedef struct flood_s
{
int playernum;
char data[2048];
float time;
} flood_t;
@ -492,47 +493,31 @@ static void UnignoreteamAll_f (void)
Con_Printf("Team ignore list cleared\n");
}
char Ignore_Check_Flood(char *s, int flags, int offset)
char Ignore_Check_Flood(player_info_t *sender, const char *s, int flags)
{
int i, p, q, len;
char name[MAX_INFO_KEY];
int i;
int slot;
if ( !(
( (ignore_flood.value == 1 && (flags & TPM_NORMAL || flags & TPM_SPECTATOR)) ||
( (ignore_flood.value == 1 && ((flags & TPM_NORMAL) || (flags & TPM_SPECTATOR))) ||
(ignore_flood.value == 2 && flags != 0) )
) )
{
return NO_IGNORE_NO_ADD;
}
if (flags == 1 || flags == TPM_SPECTATOR)
{
p = 0;
q = offset - 3;
}
else if (flags == TPM_TEAM)
{
p = 1;
q = offset - 4;
}
else if (flags == 8)
{
p = 7;
q = offset -3;
}
else
if (!sender) //don't ignore system messages.
return NO_IGNORE_NO_ADD;
len = bound (0, q - p + 1, sizeof(name) - 1);
slot = sender - cl.players;
Q_strncpyz(name, s + p, len + 1);
if (!cls.demoplayback && !strcmp(name, Player_MyName()))
if (!cls.demoplayback && !strcmp(sender->name, Player_MyName()))
{
return NO_IGNORE_NO_ADD;
}
for (i = 0; i < FLOODLIST_SIZE; i++)
{
if (floodlist[i].data[0] && !strncmp(floodlist[i].data, s, sizeof(floodlist[i].data) - 1) &&
if (floodlist[i].playernum == slot && floodlist[i].data[0] && !strncmp(floodlist[i].data, s, sizeof(floodlist[i].data) - 1) &&
realtime - floodlist[i].time < ignore_flood_duration.value) {
return IGNORE_NO_ADD;
}
@ -540,8 +525,9 @@ char Ignore_Check_Flood(char *s, int flags, int offset)
return NO_IGNORE_ADD;
}
void Ignore_Flood_Add(char *s)
void Ignore_Flood_Add(player_info_t *sender, const char *s)
{
floodlist[floodindex].playernum = sender - cl.players;
floodlist[floodindex].data[0] = 0;
Q_strncpyz(floodlist[floodindex].data, s, sizeof(floodlist[floodindex].data));
floodlist[floodindex].time = realtime;
@ -551,10 +537,9 @@ void Ignore_Flood_Add(char *s)
}
qboolean Ignore_Message(char *s, int flags, int offset)
qboolean Ignore_Message(const char *sendername, const char *s, int flags)
{
int slot, i, p, q, len;
char name[MAX_SCOREBOARDNAME];
int slot, i;
if (!ignore_mode.ival && (flags & 2))
return false;
@ -565,35 +550,14 @@ qboolean Ignore_Message(char *s, int flags, int offset)
else if (ignore_spec.ival == 1 && (flags == 4) && !cl.spectator)
return true;
if (flags == 1 || flags == 4)
{
p = 0;
q = offset - 3;
}
else if (flags == 2)
{
p = 1;
q = offset - 4;
}
else if (flags == 8)
{
p = 7;
q = offset - 3;
}
else
{
if (!sendername)
return false;
}
len = bound (0, q - p + 1, sizeof(name) - 1);
Q_strncpyz(name, s + p, len + 1);
if ((slot = Player_NametoSlot(name)) == PLAYER_NAME_NOMATCH)
if ((slot = Player_NametoSlot(sendername)) == PLAYER_NAME_NOMATCH)
return false;
if (IsIgnored(slot))
return true;
if (ignore_opponents.ival && (
(int) ignore_opponents.ival == 1 ||
@ -610,7 +574,7 @@ qboolean Ignore_Message(char *s, int flags, int offset)
if (!cl.teamplay)
return false;
if (cl.players[slot].spectator || !strcmp(Player_MyName(), name))
if (cl.players[slot].spectator || !strcmp(Player_MyName(), sendername))
return false;
for (i = 0; i < MAX_TEAMIGNORELIST && ignoreteamlist[i][0]; i++)

View File

@ -28,9 +28,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define IGNORE_NO_ADD 2
void Ignore_Init(void);
qboolean Ignore_Message(char *s, int flags, int offset);
char Ignore_Check_Flood(char *s, int flags, int offset);
void Ignore_Flood_Add(char *s);
qboolean Ignore_Message(const char *sendername, const char *s, int flags);
char Ignore_Check_Flood(player_info_t *sender, const char *s, int flags);
void Ignore_Flood_Add(player_info_t *sender, const char *s);
void Ignore_ResetFloodList(void);
#endif

View File

@ -847,6 +847,9 @@ void CL_ClampPitch (int pnum)
pv->viewangles[PITCH] += pv->viewanglechange[PITCH];
pv->viewangles[YAW] += pv->viewanglechange[YAW];
pv->viewangles[ROLL] += pv->viewanglechange[ROLL];
pv->viewangles[YAW] /= 360;
pv->viewangles[YAW] = pv->viewangles[YAW] - (int)pv->viewangles[YAW];
pv->viewangles[YAW] *= 360;
VectorClear(pv->viewanglechange);
#ifdef Q2CLIENT

View File

@ -134,7 +134,7 @@ cvar_t cl_teamchatsound = CVAR("cl_teamchatsound", "misc/talk.wav");
cvar_t r_torch = CVARF("r_torch", "0", CVAR_CHEAT);
cvar_t r_rocketlight = CVARFC("r_rocketlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback);
cvar_t r_lightflicker = CVAR("r_lightflicker", "1");
cvar_t cl_r2g = CVARF("cl_r2g", "0", CVAR_ARCHIVE);
cvar_t cl_r2g = CVARFD("cl_r2g", "0", CVAR_ARCHIVE, "Uses progs/grenade.mdl instead of progs/missile.mdl when 1.");
cvar_t r_powerupglow = CVAR("r_powerupglow", "1");
cvar_t v_powerupshell = CVARF("v_powerupshell", "0", CVAR_ARCHIVE);
cvar_t cl_gibfilter = CVARF("cl_gibfilter", "0", CVAR_ARCHIVE);
@ -298,7 +298,7 @@ void CL_UpdateWindowTitle(void)
default:
#ifndef CLIENTONLY
if (sv.state)
Q_snprintfz(title, sizeof(title), "%s: %s", fs_gamename.string, sv.name);
Q_snprintfz(title, sizeof(title), "%s: %s", fs_gamename.string, svs.name);
else
#endif
if (cls.demoplayback)
@ -337,6 +337,7 @@ void CL_MakeActive(char *gamename)
//kill models left over from the last map.
Mod_Purge(MP_MAPCHANGED);
Image_Purge();
//and reload shaders now if needed (this was blocked earlier)
Shader_DoReload();
@ -708,6 +709,7 @@ void CL_CheckForResend (void)
#ifndef CLIENTONLY
if (!cls.state && (!connectinfo.trying || sv.state != ss_clustermode) && sv.state)
{
extern cvar_t dpcompat_nopreparse;
unsigned int pext1, pext2;
pext1 = 0;
pext2 = 0;
@ -784,6 +786,22 @@ void CL_CheckForResend (void)
{
cls.protocol = CP_NETQUAKE;
cls.protocol_nq = CPNQ_FITZ666;
//FIXME: pext
}
if (dpcompat_nopreparse.ival)
{
if (progstype == PROG_QW && cls.protocol != CP_QUAKEWORLD)
{
cls.protocol = CP_QUAKEWORLD;
pext1 = Net_PextMask(1, false);
pext2 = Net_PextMask(2, false);
}
else if (progstype != PROG_QW && cls.protocol == CP_QUAKEWORLD)
{
cls.protocol = CP_NETQUAKE;
cls.protocol_nq = CPNQ_DP7; //dpcompat_nopreparse is only really needed for DP mods that send unknowable svc_tempentity messages to the client.
}
}
//make sure the protocol within demos is actually correct/sane
@ -1306,24 +1324,24 @@ void CL_BlendFog(fogstate_t *result, fogstate_t *oldf, float time, fogstate_t *n
result->time = time;
}
void CL_ResetFog(void)
void CL_ResetFog(int ftype)
{
//blend from the current state, not the old state. this means things work properly if we've not reached the new state yet.
CL_BlendFog(&cl.oldfog, &cl.oldfog, realtime, &cl.fog);
CL_BlendFog(&cl.oldfog[ftype], &cl.oldfog[ftype], realtime, &cl.fog[ftype]);
//reset the new state to defaults, to be filled in by the caller.
memset(&cl.fog, 0, sizeof(cl.fog));
cl.fog.time = realtime;
cl.fog.density = 0;
cl.fog.colour[0] = 0.3;
cl.fog.colour[1] = 0.3;
cl.fog.colour[2] = 0.3;
cl.fog.alpha = 1;
cl.fog.depthbias = 0;
memset(&cl.fog[ftype], 0, sizeof(cl.fog[ftype]));
cl.fog[ftype].time = realtime;
cl.fog[ftype].density = 0;
cl.fog[ftype].colour[0] = 0.3;
cl.fog[ftype].colour[1] = 0.3;
cl.fog[ftype].colour[2] = 0.3;
cl.fog[ftype].alpha = 1;
cl.fog[ftype].depthbias = 0;
/*
cl.fog.end = 16384;
cl.fog.height = 1<<30;
cl.fog.fadedepth = 128;
cl.fog[ftype].end = 16384;
cl.fog[ftype].height = 1<<30;
cl.fog[ftype].fadedepth = 128;
*/
}
@ -1352,7 +1370,6 @@ void CL_ClearState (void)
S_StopAllSounds (true);
S_UntouchAll();
S_ResetFailedLoad();
r_regsequence++;
Cvar_ApplyLatches(CVAR_SERVEROVERRIDE);
@ -1364,6 +1381,7 @@ void CL_ClearState (void)
SV_UnspawnServer();
#endif
Mod_ClearAll ();
r_regsequence++;
Cvar_ApplyLatches(CVAR_LATCH);
}
@ -1440,7 +1458,8 @@ void CL_ClearState (void)
// wipe the entire cl structure
memset (&cl, 0, sizeof(cl));
CL_ResetFog();
CL_ResetFog(0);
CL_ResetFog(1);
cl.allocated_client_slots = QWMAX_CLIENTS;
#ifndef CLIENTONLY
@ -3548,52 +3567,53 @@ void CL_FTP_f(void)
//fixme: make a cvar
void CL_Fog_f(void)
{
int ftype = strcmp(Cmd_Argv(0), "fog");
if ((cl.fog_locked && !Cmd_FromGamecode()) || Cmd_Argc() <= 1)
Con_Printf("Current fog %f (r:%f g:%f b:%f, a:%f bias:%f)\n", cl.fog.density, cl.fog.colour[0], cl.fog.colour[1], cl.fog.colour[2], cl.fog.alpha, cl.fog.depthbias);
Con_Printf("Current fog %f (r:%f g:%f b:%f, a:%f bias:%f)\n", cl.fog[ftype].density, cl.fog[ftype].colour[0], cl.fog[ftype].colour[1], cl.fog[ftype].colour[2], cl.fog[ftype].alpha, cl.fog[ftype].depthbias);
else
{
CL_ResetFog();
CL_ResetFog(ftype);
switch(Cmd_Argc())
{
case 1:
break;
case 2:
cl.fog.density = atof(Cmd_Argv(1));
cl.fog[ftype].density = atof(Cmd_Argv(1));
break;
case 3:
cl.fog.density = atof(Cmd_Argv(1));
cl.fog.colour[0] = cl.fog.colour[1] = cl.fog.colour[2] = atof(Cmd_Argv(2));
cl.fog[ftype].density = atof(Cmd_Argv(1));
cl.fog[ftype].colour[0] = cl.fog[ftype].colour[1] = cl.fog[ftype].colour[2] = atof(Cmd_Argv(2));
break;
case 4:
cl.fog.density = 0.05; //make something up for vauge compat with fitzquake, so it doesn't get the default of 0
cl.fog.colour[0] = atof(Cmd_Argv(1));
cl.fog.colour[1] = atof(Cmd_Argv(2));
cl.fog.colour[2] = atof(Cmd_Argv(3));
cl.fog[ftype].density = 0.05; //make something up for vauge compat with fitzquake, so it doesn't get the default of 0
cl.fog[ftype].colour[0] = atof(Cmd_Argv(1));
cl.fog[ftype].colour[1] = atof(Cmd_Argv(2));
cl.fog[ftype].colour[2] = atof(Cmd_Argv(3));
break;
case 5:
default:
cl.fog.density = atof(Cmd_Argv(1));
cl.fog.colour[0] = atof(Cmd_Argv(2));
cl.fog.colour[1] = atof(Cmd_Argv(3));
cl.fog.colour[2] = atof(Cmd_Argv(4));
cl.fog[ftype].density = atof(Cmd_Argv(1));
cl.fog[ftype].colour[0] = atof(Cmd_Argv(2));
cl.fog[ftype].colour[1] = atof(Cmd_Argv(3));
cl.fog[ftype].colour[2] = atof(Cmd_Argv(4));
break;
}
if (cls.state == ca_active)
cl.fog.time += 1;
cl.fog[ftype].time += 1;
//fitz:
//if (Cmd_Argc() >= 6) cl.fog_time += atof(Cmd_Argv(5));
//dp:
if (Cmd_Argc() >= 6) cl.fog.alpha = atof(Cmd_Argv(5));
if (Cmd_Argc() >= 7) cl.fog.depthbias = atof(Cmd_Argv(6));
if (Cmd_Argc() >= 6) cl.fog[ftype].alpha = atof(Cmd_Argv(5));
if (Cmd_Argc() >= 7) cl.fog[ftype].depthbias = atof(Cmd_Argv(6));
//if (Cmd_Argc() >= 8) cl.fog.end = atof(Cmd_Argv(7));
//if (Cmd_Argc() >= 9) cl.fog.height = atof(Cmd_Argv(8));
//if (Cmd_Argc() >= 10) cl.fog.fadedepth = atof(Cmd_Argv(9));
if (Cmd_FromGamecode())
cl.fog_locked = !!cl.fog.density;
cl.fog_locked = !!cl.fog[ftype].density;
}
}
@ -3924,6 +3944,7 @@ void CL_Init (void)
Cmd_AddCommand ("topten", NULL);
Cmd_AddCommandD ("fog", CL_Fog_f, "fog <density> <red> <green> <blue> <alpha> <depthbias>");
Cmd_AddCommandD ("waterfog", CL_Fog_f, "waterfog <density> <red> <green> <blue> <alpha> <depthbias>");
Cmd_AddCommand ("kill", NULL);
Cmd_AddCommand ("pause", NULL);
Cmd_AddCommand ("say", CL_Say_f);
@ -4673,7 +4694,7 @@ double Host_Frame (double time)
static double time1 = 0;
static double time2 = 0;
static double time3 = 0;
int pass0, pass1, pass2, pass3;
int pass0, pass1, pass2, pass3, i;
// float fps;
double newrealtime;
static double spare;
@ -4924,12 +4945,15 @@ 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;
for (i = 0; i < MAX_SPLITS; i++)
{
cl.playerview[i].audio.defaulted = true;
VectorClear(cl.playerview[i].audio.origin);
VectorSet(cl.playerview[i].audio.forward, 1, 0, 0);
VectorSet(cl.playerview[i].audio.right, 0, 1, 0);
VectorSet(cl.playerview[i].audio.up, 0, 0, 1);
cl.playerview[i].audio.inwater = false;
}
if (SCR_UpdateScreen && !vid.isminimized)
{
@ -4947,8 +4971,11 @@ double Host_Frame (double time)
time2 = Sys_DoubleTime ();
// update audio
S_UpdateListener (r_refdef.audio.origin, r_refdef.audio.forward, r_refdef.audio.right, r_refdef.audio.up);
S_SetUnderWater(r_refdef.audio.inwater);
for (i = 0 ; i < MAX_SPLITS; i++)
{
playerview_t *pv = &cl.playerview[cl.splitclients?i % cl.splitclients:0];
S_UpdateListener (i, pv->audio.origin, pv->audio.forward, pv->audio.right, pv->audio.up, pv->audio.inwater);
}
S_Update ();

View File

@ -2283,7 +2283,7 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype)
for (b = dl->dlblocks; b; b = n)
{
if (b->state == DLB_RECEIVED)
VFS_PRINTF(parts, "c %#llx %#llx\n", (long long)b->start, (long long)b->end);
VFS_PRINTF(parts, "c "fPRIllx" "fPRIllx"\n", (long long)b->start, (long long)b->end);
else
{
for(;;)
@ -2298,7 +2298,7 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype)
}
break;
}
VFS_PRINTF(parts, "m %#llx %#llx\n", (long long)b->start, (long long)b->end);
VFS_PRINTF(parts, "m "fPRIllx" "fPRIllx"\n", (long long)b->start, (long long)b->end);
}
n = b->next;
@ -3888,7 +3888,7 @@ void CLQ2_ParseConfigString (void)
}
else if (i == Q2CS_CDTRACK)
{
Media_BackgroundTrack (s, NULL);
Media_NamedTrack (s, NULL);
}
else if (i >= Q2CS_MODELS && i < Q2CS_MODELS+Q2MAX_MODELS)
{
@ -4050,6 +4050,7 @@ Static entities are non-interactive world objects
like torches
=====================
*/
void R_StaticEntityToRTLight(int i);
void CL_ParseStatic (int version)
{
entity_t *ent;
@ -4168,6 +4169,11 @@ void CL_ParseStatic (int version)
VectorCopy(es.origin, maxs);
}
cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[i].pvscache, mins, maxs);
#ifdef RTLIGHTS
//and now handle any rtlight fields on it
R_StaticEntityToRTLight(i);
#endif
}
/*
@ -4246,7 +4252,7 @@ void CLQW_ParseStartSoundPacket(void)
Host_EndGame ("CL_ParseStartSoundPacket: ent = %i", ent);
#ifdef PEXT_CSQC
if (!CSQC_StartSound(ent, channel, cl.sound_name[sound_num], pos, volume/255.0, attenuation, 100))
if (!CSQC_StartSound(ent, channel, cl.sound_name[sound_num], pos, volume/255.0, attenuation, 100, 0))
#endif
{
if (!sound_num)
@ -4347,23 +4353,24 @@ void CLQ2_ParseStartSoundPacket(void)
#if defined(NQPROT) || defined(PEXT_SOUNDDBL)
void CLNQ_ParseStartSoundPacket(void)
{
vec3_t pos;
int channel, ent;
int sound_num;
int volume;
int field_mask;
float attenuation;
vec3_t pos;
int channel, ent;
int sound_num;
int volume;
int field_mask;
float attenuation;
int i;
int pitchadj;
float timeofs;
field_mask = MSG_ReadByte();
field_mask = MSG_ReadByte();
if (field_mask & NQSND_VOLUME)
if (field_mask & NQSND_VOLUME)
volume = MSG_ReadByte ();
else
volume = DEFAULT_SOUND_PACKET_VOLUME;
if (field_mask & NQSND_ATTENUATION)
if (field_mask & NQSND_ATTENUATION)
attenuation = MSG_ReadByte () / 64.0;
else
attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
@ -4373,6 +4380,11 @@ void CLNQ_ParseStartSoundPacket(void)
else
pitchadj = 100;
if (field_mask & FTESND_TIMEOFS)
timeofs = MSG_ReadShort() / 1000.0;
else
timeofs = 0;
if (field_mask & DPSND_LARGEENTITY)
{
ent = MSGCL_ReadEntity();
@ -4400,13 +4412,13 @@ void CLNQ_ParseStartSoundPacket(void)
pos[i] = MSG_ReadCoord ();
#ifdef PEXT_CSQC
if (!CSQC_StartSound(ent, channel, cl.sound_name[sound_num], pos, volume/255.0, attenuation, pitchadj))
if (!CSQC_StartSound(ent, channel, cl.sound_name[sound_num], pos, volume/255.0, attenuation, pitchadj, timeofs))
#endif
{
if (!sound_num)
S_StopSound(ent, channel);
else
S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation, 0, pitchadj);
S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation, timeofs, pitchadj);
}
if (ent == cl.playerview[0].playernum+1)
@ -4493,7 +4505,7 @@ void CL_NewTranslation (int slot)
if (player->model->loadstate == MLS_FAILED && strcmp(mod, "male"))
{ //fall back on male if the model doesn't exist. yes, sexist.
mod = "male";
player->model = Mod_ForName(va("players/male/tris.md2", mod), 0);
player->model = Mod_ForName(va("players/%s/tris.md2", mod), 0);
}
player->skinid = Mod_RegisterSkinFile(va("players/%s/%s.skin", mod,skin));
if (!player->skinid)
@ -5217,11 +5229,11 @@ char *CL_ParseChat(char *text, player_info_t **player, int *msgflags)
if ((int)msg_filter.value & flags)
return NULL; //filter chat
check_flood = Ignore_Check_Flood(s, flags, offset);
check_flood = Ignore_Check_Flood(*player, s, flags);
if (check_flood == IGNORE_NO_ADD)
return NULL;
else if (check_flood == NO_IGNORE_ADD)
Ignore_Flood_Add(s);
Ignore_Flood_Add(*player, s);
}
#ifdef PLUGINS
else
@ -7264,13 +7276,13 @@ void CLNQ_ParseServerMessage (void)
Cmd_ExecuteString("bf", RESTRICT_SERVER);
break;
case svcfitz_fog:
CL_ResetFog();
cl.fog.density = MSG_ReadByte()/255.0f;
cl.fog.colour[0] = MSG_ReadByte()/255.0f;
cl.fog.colour[1] = MSG_ReadByte()/255.0f;
cl.fog.colour[2] = MSG_ReadByte()/255.0f;
cl.fog.time += ((unsigned short)MSG_ReadShort()) / 100.0;
cl.fog_locked = !!cl.fog.density;
CL_ResetFog(0);
cl.fog[0].density = MSG_ReadByte()/255.0f;
cl.fog[0].colour[0] = MSG_ReadByte()/255.0f;
cl.fog[0].colour[1] = MSG_ReadByte()/255.0f;
cl.fog[0].colour[2] = MSG_ReadByte()/255.0f;
cl.fog[0].time += ((unsigned short)MSG_ReadShort()) / 100.0;
cl.fog_locked = !!cl.fog[0].density;
break;
case svcfitz_spawnbaseline2:
i = MSGCL_ReadEntity ();

View File

@ -661,7 +661,7 @@ static qintptr_t VARGS Plug_GetNetworkInfo(void *offset, quintptr_t mask, const
if (has(mlatency))
outptr->mlatency = 0;
if (has(mrate))
outptr->mrate = 0;
outptr->mrate = IN_DetermineMouseRate();
if (has(vlatency))
outptr->vlatency = 0;

View File

@ -754,16 +754,11 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st
}
else
VectorScale(state->u.q1.velocity, 1/8.0, plstate->velocity);
VectorCopy(state->angles, plstate->viewangles);
// plstate->viewangles[2] = V_CalcRoll(plstate->viewangles, plstate->velocity);
plstate->viewangles[0] = SHORT2ANGLE(state->u.q1.vangle[0]);
plstate->viewangles[1] = SHORT2ANGLE(state->u.q1.vangle[1]);
plstate->viewangles[2] = SHORT2ANGLE(state->u.q1.vangle[2]);
if (state->u.q1.pmovetype)
plstate->viewangles[0] *= -3;
a[0] = ((-192-state->u.q1.gravitydir[0])/256.0f) * 360;
a[1] = (state->u.q1.gravitydir[1]/256.0f) * 360;
a[2] = 0;

View File

@ -619,7 +619,7 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
x = left;
else
{
x = (right + left - Font_LineWidth(line_start[l], line_end[l]))/2;
x = left + (right - left - Font_LineWidth(line_start[l], line_end[l]))/2;
}
remaining -= line_end[l]-line_start[l];
@ -763,6 +763,9 @@ void SCR_DrawCursor(void)
return;
//system doesn't support a hardware cursor, so try to draw a software one.
if (!*key_customcursor[cmod].name)
return;
p = R2D_SafeCachePic(key_customcursor[cmod].name);
if (!p || !R_GetShaderSizes(p, NULL, NULL, false))
p = R2D_SafeCachePic("gfx/cursor.lmp");
@ -1379,25 +1382,32 @@ void SCR_DrawNet (void)
R2D_ScalePic (scr_vrect.x+64, scr_vrect.y, 64, 64, scr_net);
}
//FIXME: no support for UTF-8 input
void SCR_StringXY(char *str, float x, float y)
{
char *s2;
int px, py;
unsigned int codepoint;
int error;
Font_BeginString(font_default, ((x<0)?vid.width:x), ((y<0)?vid.height - sb_lines:y), &px, &py);
if (x < 0)
{
for (s2 = str; *s2; s2++)
px -= Font_CharWidth(CON_WHITEMASK, *s2);
for (s2 = str; *s2; )
{
codepoint = unicode_decode(&error, s2, &s2, true);
px -= Font_CharWidth(CON_WHITEMASK, codepoint);
}
}
if (y < 0)
py += y*Font_CharHeight();
while (*str)
px = Font_DrawChar(px, py, CON_WHITEMASK, *str++);
{
codepoint = unicode_decode(&error, str, &str, true);
px = Font_DrawChar(px, py, CON_WHITEMASK, codepoint);
}
Font_EndString(font_default);
}
@ -2482,16 +2492,16 @@ void SCR_BringDownConsole (void)
cl.cshifts[CSHIFT_CONTENTS].percent = 0; // no area contents palette on next frame
}
void SCR_TileClear (void)
void SCR_TileClear (int skipbottom)
{
if (r_refdef.vrect.width < r_refdef.grect.width)
{
float w;
// left
R2D_TileClear (r_refdef.grect.x, r_refdef.grect.y, r_refdef.vrect.x-r_refdef.grect.x, r_refdef.grect.height - sb_lines);
R2D_TileClear (r_refdef.grect.x, r_refdef.grect.y, r_refdef.vrect.x-r_refdef.grect.x, r_refdef.grect.height - skipbottom);
// right
w = (r_refdef.grect.x+r_refdef.grect.width) - (r_refdef.vrect.x+r_refdef.vrect.width);
R2D_TileClear ((r_refdef.grect.x+r_refdef.grect.width) - (w), r_refdef.grect.y, w, r_refdef.grect.height - sb_lines);
R2D_TileClear ((r_refdef.grect.x+r_refdef.grect.width) - (w), r_refdef.grect.y, w, r_refdef.grect.height - skipbottom);
}
if (r_refdef.vrect.height < r_refdef.grect.height)
{
@ -2503,7 +2513,7 @@ void SCR_TileClear (void)
R2D_TileClear (r_refdef.vrect.x,
r_refdef.vrect.y + r_refdef.vrect.height,
r_refdef.vrect.width,
(r_refdef.grect.y+r_refdef.grect.height) - sb_lines - (r_refdef.vrect.y + r_refdef.vrect.height));
(r_refdef.grect.y+r_refdef.grect.height) - skipbottom - (r_refdef.vrect.y + r_refdef.vrect.height));
}
}

View File

@ -2434,9 +2434,9 @@ static struct{
#define ATTN_NONE 0
#define ATTN_NORM 1
#define ATTN_STATIC 1
void Q2S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
void Q2S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float delay)
{
S_StartSound(entnum, entchannel, sfx, origin, fvol, attenuation, timeofs, 0);
S_StartSound(entnum, entchannel, sfx, origin, fvol, attenuation, -delay, 0);
}
void CLQ2_ParseTEnt (void)
{
@ -3401,7 +3401,7 @@ void CL_UpdateBeams (void)
int i, j;
beam_t *b;
vec3_t dist, org;
float *vieworg, *viewang;
float *vieworg;
float d;
entity_t *ent;
entity_state_t *st;
@ -3447,7 +3447,7 @@ void CL_UpdateBeams (void)
// pl = &cl.inframes[cl.parsecount&UPDATE_MASK].playerstate[b->entity-1];
// if (pl->messagenum == cl.parsecount || cls.protocol == CP_NETQUAKE)
{
vec3_t fwd, org, ang;
vec3_t fwd, org, ang, viewang;
float delta, f, len;
// if (cl.spectator && pv->cam_auto)
@ -3456,15 +3456,16 @@ void CL_UpdateBeams (void)
// }
// else
vieworg = pv->simorg;
viewang = pv->simangles;
if (cl_truelightning.ival >= 2 && cls.netchan.outgoing_sequence > cl_truelightning.ival)
if (cl_truelightning.ival > 1 && cl.movesequence > cl_truelightning.ival)
{
inframe_t *frame = &cl.inframes[(cls.netchan.outgoing_sequence-cl_truelightning.ival)&UPDATE_MASK];
viewang = frame->playerstate[pv->playernum].viewangles;
viewang[0] = (frame->playerstate[pv->playernum].command.angles[0] * 360) / 65336.0;
viewang[1] = (frame->playerstate[pv->playernum].command.angles[1] * 360) / 65336.0;
outframe_t *frame = &cl.outframes[(cl.movesequence-cl_truelightning.ival)&UPDATE_MASK];
viewang[0] = SHORT2ANGLE(frame->cmd[j].angles[0]);
viewang[1] = SHORT2ANGLE(frame->cmd[j].angles[1]);
viewang[2] = SHORT2ANGLE(frame->cmd[j].angles[2]);
}
else
VectorCopy(pv->simangles, viewang);
VectorCopy (vieworg, b->start);
b->start[2] += pv->crouch + bound(-7, v_viewheight.value, 4);
@ -3486,7 +3487,7 @@ void CL_UpdateBeams (void)
ang[0] += (viewang[0] - ang[0]) * f;
// lerp yaw
delta = viewang[1] - ang[1];
delta = anglemod(viewang[1] - ang[1]);
if (delta > 180)
delta -= 360;
if (delta < -180)

View File

@ -953,7 +953,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
if (VM_LONG(arg[0]) < 0 || VM_LONG(arg[0]) > 255 || (int)arg[1] + VM_LONG(arg[2]) >= mask || VM_POINTER(arg[1]) < offset || VM_LONG(arg[2]) < 1)
break; //out of bounds.
Q_strncpyz(VM_POINTER(arg[1]), Key_KeynumToString(VM_LONG(arg[0])), VM_LONG(arg[2]));
Q_strncpyz(VM_POINTER(arg[1]), Key_KeynumToString(VM_LONG(arg[0]), 0), VM_LONG(arg[2]));
break;
case UI_KEY_GETBINDINGBUF:

View File

@ -665,6 +665,16 @@ struct playerview_s
int prevframe;
int oldframe;
} vm;
struct
{
qboolean defaulted;
vec3_t origin;
vec3_t forward;
vec3_t right;
vec3_t up;
int inwater;
} audio;
};
//
@ -789,8 +799,8 @@ typedef struct
vec3_t skyaxis;
qboolean fog_locked;
fogstate_t fog;
fogstate_t oldfog;
fogstate_t fog[2]; //0 = air, 1 = water. if water has no density fall back on air.
fogstate_t oldfog[2];
char levelname[40]; // for display on solo scoreboard
@ -1071,9 +1081,11 @@ void CL_BaseMove (usercmd_t *cmd, int pnum, float extra, float wantfps);
int Master_FindBestRoute(char *server, char *out, size_t outsize, int *directcost, int *chainedcost);
float CL_KeyState (kbutton_t *key, int pnum, qboolean noslowstart);
char *Key_KeynumToString (int keynum);
char *Key_KeynumToString (int keynum, int modifier);
int Key_StringToKeynum (const char *str, int *modifier);
char *Key_GetBinding(int keynum);
char *Key_GetBinding(int keynum, int bindmap, int modifier);
void Key_GetBindMap(int *bindmaps);
void Key_SetBindMap(int *bindmaps);
void CL_UseIndepPhysics(qboolean allow);
@ -1083,8 +1095,6 @@ float CL_FilterTime (double time, float wantfps, qboolean ignoreserver);
int CL_RemoveClientCommands(char *command);
void CL_AllowIndependantSendCmd(qboolean allow);
void CL_DrawPrydonCursor(void);
//
// cl_demo.c
//
@ -1284,7 +1294,7 @@ qboolean CSQC_MouseMove(float xdelta, float ydelta, int devid);
qboolean CSQC_MousePosition(float xabs, float yabs, int devid);
qboolean CSQC_JoystickAxis(int axis, float value, 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);
int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod, float timeofs);
void CSQC_ParseEntities(void);
void CSQC_ResetTrails(void);
@ -1501,7 +1511,7 @@ struct cin_s *Media_StartCin(char *name);
texid_tf Media_UpdateForShader(cin_t *cin);
void Media_ShutdownCin(cin_t *cin);
#endif
qboolean Media_BackgroundTrack(const char *initialtrack, const char *looptrack); //new background music interface
qboolean Media_NamedTrack(const char *initialtrack, const char *looptrack); //new background music interface
void Media_NumberedTrack(unsigned int initialtrack, unsigned int looptrack); //legacy cd interface for protocols that only support numbered tracks.
void Media_EndedTrack(void); //cd is no longer running, media code needs to pick a new track (cd track or faketrack)

View File

@ -878,7 +878,7 @@ void SV_FlushRedirect (void);
#define MAXPRINTMSG 4096
static void Con_PrintFromThread (void *ctx, void *data, size_t a, size_t b)
{
Con_Printf("%s", data);
Con_Printf("%s", (char*)data);
BZ_Free(data);
}
@ -1154,7 +1154,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
cursorframe = ((int)(realtime*con_cursorspeed)&1);
//FIXME: support tab somehow
for (lhs = 0, cchar = maskedtext-1; cchar < cursor; )
for (lhs = 0, cchar = maskedtext; cchar < cursor; )
{
cchar = Font_Decode(cchar, &codeflags, &codepoint);
lhs += Font_CharWidth(codeflags, codepoint);
@ -1181,7 +1181,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
lhs = Font_DrawChar(lhs, y, codeflags, codepoint);
}
rhs = x;
Font_Decode(cursor, &codeflags, &codepoint);
cchar = Font_Decode(cursor, &codeflags, &codepoint);
if (cursorframe)
{
// extern cvar_t com_parseutf8;
@ -1190,15 +1190,18 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
// else
Font_DrawChar(rhs, y, CON_WHITEMASK, 0xe000|11);
}
else if (*cursor)
else if (codepoint)
{
Font_DrawChar(rhs, y, codeflags, codepoint);
}
rhs += Font_CharWidth(codeflags, codepoint);
for (cchar = cursor+1; *cchar; )
if (codepoint)
{
cchar = Font_Decode(cchar, &codeflags, &codepoint);
rhs = Font_DrawChar(rhs, y, codeflags, codepoint);
rhs += Font_CharWidth(codeflags, codepoint);
while (*cchar)
{
cchar = Font_Decode(cchar, &codeflags, &codepoint);
rhs = Font_DrawChar(rhs, y, codeflags, codepoint);
}
}
/*if its getting completed to something, show some help about the command that is going to be used*/

View File

@ -1,6 +1,8 @@
#include "quakedef.h"
#include "shader.h"
//#define PURGEIMAGES //somewhat experimental still. we're still flushing more than we should.
//FIXME
texid_t GL_FindTextureFallback (const char *identifier, unsigned int flags, void *fallback, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt);
//FIXME
@ -3444,6 +3446,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
{
unsigned int *rgbadata = rawdata;
int i;
qboolean valid;
mips->mip[0].width = imgwidth;
mips->mip[0].height = imgheight;
@ -3604,16 +3607,24 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
case TF_TRANS8_FULLBRIGHT:
mips->encoding = PTI_RGBA8;
rgbadata = BZ_Malloc(imgwidth * imgheight*4);
for (i = 0; i < imgwidth * imgheight; i++)
for (i = 0, valid = false; i < imgwidth * imgheight; i++)
{
if (((qbyte*)rawdata)[i] < 255-vid.fullbright)
if (((qbyte*)rawdata)[i] < 256-vid.fullbright)
rgbadata[i] = 0;
else
{
rgbadata[i] = d_8to24rgbtable[((qbyte*)rawdata)[i]];
valid = true;
}
}
if (freedata)
BZ_Free(rawdata);
freedata = true;
if (!valid)
{
BZ_Free(rgbadata);
return false;
}
break;
case TF_HEIGHT8PAL:
@ -3641,6 +3652,27 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
freedata = true;
break;
case TF_BGR24_FLIP:
mips->encoding = PTI_RGBX8;
rgbadata = BZ_Malloc(imgwidth * imgheight*4);
for (i = 0; i < imgheight; i++)
{
int x;
qbyte *in = (qbyte*)rawdata + (imgheight-i-1) * imgwidth * 3;
qbyte *out = (qbyte*)rgbadata + i * imgwidth * 4;
for (x = 0; x < imgwidth; x++, in+=3, out+=4)
{
out[0] = in[2];
out[1] = in[1];
out[2] = in[0];
out[3] = 0xff;
}
}
if (freedata)
BZ_Free(rawdata);
freedata = true;
break;
case TF_8PAL24:
if (!palettedata)
{
@ -3723,7 +3755,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
mips->encoding = PTI_RGBX8;
break;
case PTI_BGRA8:
mips->encoding = PTI_RGBX8;
mips->encoding = PTI_BGRX8;
break;
case PTI_RGBA16F:
case PTI_RGBA32F:
@ -3823,6 +3855,10 @@ static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawd
if (!Image_GenMip0(mips, flags, rawdata, palettedata, imgwidth, imgheight, fmt, true))
{
Z_Free(mips);
if (flags & IF_NOWORKER)
Image_LoadTexture_Failed(tex, NULL, 0, 0);
else
COM_AddWork(0, Image_LoadTexture_Failed, tex, NULL, 0, 0);
return false;
}
Image_GenerateMips(mips, flags);
@ -4264,15 +4300,22 @@ void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t b)
image_t *Image_FindTexture(const char *identifier, const char *subdir, unsigned int flags)
{
image_t *tex;
if (!subdir)
subdir = "";
tex = Hash_Get(&imagetable, identifier);
while(tex)
{
if ((tex->flags ^ flags) & IF_CLAMP)
if (!((tex->flags ^ flags) & IF_CLAMP))
{
tex = Hash_GetNext(&imagetable, identifier, tex);
continue;
#ifdef PURGEIMAGES
if (!strcmp(subdir, tex->subpath?tex->subpath:""))
#endif
{
tex->regsequence = r_regsequence;
return tex;
}
}
return tex;
tex = Hash_GetNext(&imagetable, identifier, tex);
}
return NULL;
}
@ -4471,6 +4514,7 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags)
{
struct pendingtextureinfo mips;
size_t i;
mips.extrafree = NULL;
mips.type = (flags & IF_3DMAP)?PTI_3D:PTI_2D;
@ -4482,6 +4526,12 @@ void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, in
tex->width = mips.mip[0].width;
tex->height = mips.mip[0].height;
tex->status = TEX_LOADED;
for (i = 0; i < mips.mipcount; i++)
if (mips.mip[i].needfree)
BZ_Free(mips.mip[i].data);
if (mips.extrafree)
BZ_Free(mips.extrafree);
}
typedef struct
@ -4593,26 +4643,68 @@ void Image_DestroyTexture(image_t *tex)
Hash_RemoveData(&imagetable, tex->ident, tex);
Z_Free(tex);
}
void Image_List_f(void)
void Shader_TouchTextures(void);
void Image_Purge(void)
{
image_t *tex;
char *status;
#ifdef PURGEIMAGES
image_t *tex, *a;
int loaded = 0, total = 0;
size_t mem = 0;
Shader_TouchTextures();
for (tex = imagelist; tex; tex = tex->next)
{
if (tex->status == TEX_LOADED)
status = "^2loaded";
else if (tex->status == TEX_FAILED)
status = "^1failed";
else if (tex->status == TEX_NOTLOADED)
status = "^5not loaded";
else
status = "^bloading";
if (tex->subpath)
Con_Printf("%s^h(%s)^h: %s\n", tex->ident, tex->subpath, status);
else
Con_Printf("%s: %s\n", tex->ident, status);
if (tex->flags & IF_NOPURGE)
continue;
if (tex->regsequence != r_regsequence)
Image_UnloadTexture(tex);
}
#endif
}
void Image_List_f(void)
{
image_t *tex, *a;
int loaded = 0, total = 0;
size_t mem = 0;
for (tex = imagelist; tex; tex = tex->next)
{
total++;
if (tex->subpath)
Con_Printf("^h(%s)^h%s: ", tex->subpath, tex->ident);
else
Con_Printf("%s: ", tex->ident);
for (a = tex->aliasof; a; a = a->aliasof)
{
if (a->subpath)
Con_Printf("^3^h(%s)^h%s: ", a->subpath, a->ident);
else
Con_Printf("^3%s: ", a->ident);
}
if (tex->status == TEX_LOADED)
{
Con_Printf("^2loaded\n");
if (!tex->aliasof)
{
mem += tex->width * tex->height * 4;
loaded++;
}
}
else if (tex->status == TEX_FAILED)
Con_Printf("^1failed\n");
else if (tex->status == TEX_NOTLOADED)
Con_Printf("^5not loaded\n");
else
Con_Printf("^bloading\n");
}
Con_Printf("%i images loaded (%i known)\n", loaded, total);
}
//may not create any images yet.
void Image_Init(void)
{

View File

@ -12,8 +12,53 @@ static cvar_t m_forcewheel_threshold = CVARD("m_forcewheel_threshold", "32", "Mo
static cvar_t m_strafeonright = CVARFD("m_strafeonright", "1", CVAR_ARCHIVE, "If 1, touching the right half of the touchscreen will strafe/move, while the left side will turn.");
static cvar_t m_fatpressthreshold = CVARFD("m_fatpressthreshold", "0.2", CVAR_ARCHIVE, "How fat your thumb has to be to register a fat press (touchscreens).");
static cvar_t m_touchmajoraxis = CVARFD("m_touchmajoraxis", "1", CVAR_ARCHIVE, "When using a touchscreen, use only the major axis for strafing.");
static cvar_t m_slidethreshold = CVARFD("m_slidethreshold", "10", CVAR_ARCHIVE, "How far your finger needs to move to be considered a slide event (touchscreens).");
static cvar_t m_slidethreshold = CVARFD("m_slidethreshold", "10", CVAR_ARCHIVE, "How far your finger needs to move to be considered a slide event (touchscreens).");
static cvar_t joy_advaxis[6] =
{
CVARD("joyadvaxisx", "4", "Provides a way to remap each joystick/controller axis.\n0:dead, 1:fwd, 2:pitch, 3:side, 4:yaw, 5:up, 6:roll"),
CVAR("joyadvaxisy", "2"),
CVAR("joyadvaxisz", "5"),
CVAR("joyadvaxisr", "3"),
CVAR("joyadvaxisu", "1"),
CVAR("joyadvaxisv", "6")
};
static cvar_t joy_advaxisscale[6] =
{
CVARD("joyadvaxisx_scale", "1.0", "Because joyadvaxisx etc can be added together, this provides a way to rescale or invert an individual axis without affecting another with the same action."),
CVAR("joyadvaxisy_scale", "1.0"),
CVAR("joyadvaxisz_scale", "1.0"),
CVAR("joyadvaxisr_scale", "1.0"),
CVAR("joyadvaxisu_scale", "1.0"),
CVAR("joyadvaxisv_scale", "1.0")
};
static cvar_t joy_anglesens[3] =
{
CVARD("joypitchsensitivity", "1.0", "Scaler value for the controller when it is at its most extreme value"),
CVAR("joyyawsensitivity", "-1.0"),
CVAR("joyrollsensitivity", "1.0")
};
static cvar_t joy_movesens[3] =
{
CVAR("joyforwardsensitivity", "1.0"),
CVAR("joysidesensitivity", "-1.0"),
CVAR("joyupsensitivity", "1.0")
};
//comments on threshholds comes from microsoft's xinput docs.
static cvar_t joy_anglethreshold[3] =
{
CVARD("joypitchthreshold", "0.19", "Values reported near the center of the analog joystick/controller are often erroneous and undesired.\nThe joystick threshholds are how much of the total values to ignore."), //8689/32767 (right thumb)
CVAR("joyyawthreshold", "0.19"), //8689/32767 (right thumb)
CVAR("joyrollthreshold", "0.118"), //30/255 (trigger)
};
static cvar_t joy_movethreshold[3] =
{
CVAR("joyforwardthreshold", "0.17"),//7849/32767 (left thumb)
CVAR("joysidethreshold", "0.17"), //7849/32767 (left thumb)
CVAR("joyupthreshold", "0.118"), //30/255 (trigger)
};
static cvar_t joy_exponent = CVARD("joyexponent", "2", "Scales joystick/controller sensitivity non-linearly to increase precision in the center.\nA value of 1 is linear.");
static cvar_t joy_radialdeadzone = CVARD("joyradialdeadzone", "1", "Treat controller dead zones as a pair, rather than per-axis.");
extern cvar_t _windowed_mouse;
@ -80,15 +125,16 @@ struct mouse_s
vec2_t old_delta; //how far its moved previously, for mouse smoothing
float wheeldelta;
int down;
unsigned int updates; //tracks updates per second
} ptr[MAXPOINTERS];
int touchcursor; //the cursor follows whichever finger was most recently pressed in preference to any mouse also on the same system
#define MAXJOYAXIS 6
#define MAXJOYSTICKS 4
#define MAXJOYSTICKS 8
struct joy_s
{
int qdeviceid;
int axis[MAXJOYAXIS];
float axis[MAXJOYAXIS];
} joy[MAXJOYSTICKS];
void IN_Shutdown(void)
@ -102,12 +148,14 @@ void IN_ReInit(void)
for (i = 0; i < MAXPOINTERS; i++)
{
memset(&ptr[i], 0, sizeof(ptr[i]));
ptr[i].type = M_INVALID;
ptr[i].qdeviceid = i;
}
for (i = 0; i < MAXJOYSTICKS; i++)
{
memset(&joy[i], 0, sizeof(joy[i]));
joy[i].qdeviceid = i;
}
@ -150,8 +198,23 @@ void IN_DeviceIDs_f(void)
INS_EnumerateDevices(NULL, IN_DeviceIDs_Enumerate);
}
float IN_DetermineMouseRate(void)
{
float time = Sys_DoubleTime();
static float timer;
static float last;
if (fabs(time - timer) > 1)
{
timer = time;
last = ptr[0].updates;
ptr[0].updates = 0;
}
return last;
}
void IN_Init(void)
{
int i;
events_avail = 0;
events_used = 0;
@ -164,6 +227,21 @@ void IN_Init(void)
Cvar_Register (&m_slidethreshold, "input controls");
Cvar_Register (&m_touchmajoraxis, "input controls");
for (i = 0; i < 6; i++)
{
Cvar_Register (&joy_advaxis[i], "input controls");
Cvar_Register (&joy_advaxisscale[i], "input controls");
}
for (i = 0; i < 3; i++)
{
Cvar_Register (&joy_anglesens[i], "input controls");
Cvar_Register (&joy_movesens[i], "input controls");
Cvar_Register (&joy_anglethreshold[i], "input controls");
Cvar_Register (&joy_movethreshold[i], "input controls");
}
Cvar_Register (&joy_exponent, "input controls");
Cvar_Register (&joy_radialdeadzone, "input controls");
Cmd_AddCommand ("in_deviceids", IN_DeviceIDs_f);
INS_Init();
@ -287,6 +365,9 @@ void IN_Commands(void)
else if (ev->mouse.z < -mfwt)
ptr[ev->devid].wheeldelta += mfwt;
}
if (ev->mouse.x || ev->mouse.y)
ptr[ev->devid].updates++;
}
break;
case IEV_MOUSEABS:
@ -320,6 +401,10 @@ void IN_Commands(void)
ptr[ev->devid].moveddist += fabs(ev->mouse.x - ptr[ev->devid].oldpos[0]) + fabs(ev->mouse.y - ptr[ev->devid].oldpos[1]);
}
if (ptr[ev->devid].delta[0] != ev->mouse.x - ptr[ev->devid].oldpos[0] ||
ptr[ev->devid].delta[1] != ev->mouse.y - ptr[ev->devid].oldpos[1])
ptr[ev->devid].updates++;
ptr[ev->devid].oldpos[0] = ev->mouse.x;
ptr[ev->devid].oldpos[1] = ev->mouse.y;
@ -573,6 +658,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
}
}
//rescales threshold-1 down 0-1
static float joydeadzone(float mag, float deadzone)
{
if (mag > 1) //erg?
@ -592,7 +678,12 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet
float mag;
vec3_t jlook, jstrafe;
int wpnum;
int wpnum, i;
for (i = 0; i < MAXJOYAXIS; i++)
if (joy->axis[i])
break;
if (i == MAXJOYAXIS)
return;
/*each device will be processed when its player comes to be processed*/
wpnum = cl.splitclients;
@ -605,29 +696,69 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet
if (wpnum != pnum)
return;
jlook[0] = joy->axis[0];
jlook[1] = joy->axis[1];
jlook[2] = joy->axis[2];
memset(jstrafe, 0, sizeof(jstrafe));
memset(jlook, 0, sizeof(jlook));
jstrafe[0] = joy->axis[3];
jstrafe[1] = joy->axis[4];
jstrafe[2] = joy->axis[5];
for (i = 0; i < 6; i++)
{
switch(joy_advaxis[i].ival)
{
default:
case 0: //dead axis
break;
case 1:
jstrafe[0] += joy->axis[i] * joy_advaxisscale[i].value;
break;
case 2:
jlook[0] += joy->axis[i] * joy_advaxisscale[i].value;
break;
case 3:
jstrafe[1] += joy->axis[i] * joy_advaxisscale[i].value;
break;
case 4:
jlook[1] += joy->axis[i] * joy_advaxisscale[i].value;
break;
case 5:
jstrafe[2] += joy->axis[i] * joy_advaxisscale[i].value;
break;
case 6:
jlook[2] += joy->axis[i] * joy_advaxisscale[i].value;
break;
}
}
//uses a radial deadzone for x+y axis, and separate out the z axis, just because most controllers are 2d affairs with any 3rd axis being a separate knob.
//deadzone values are stolen from microsoft's xinput documentation. they seem quite large to me - I guess that means that xbox controllers are just dodgy imprecise crap with excessive amounts of friction and finger grease.
mag = joydeadzone(sqrt(jlook[0]*jlook[0] + jlook[1]*jlook[1]), 0.239);
mag = pow(mag, 2);
jlook[0] *= mag;
jlook[1] *= mag;
mag = joydeadzone(fabs(jlook[2]), 0.00092);
jlook[2] *= mag;
mag = joydeadzone(sqrt(jstrafe[0]*jstrafe[0] + jstrafe[1]*jstrafe[1]), 0.265);
mag = pow(mag, 2);
jstrafe[0] *= mag;
jstrafe[1] *= mag;
mag = joydeadzone(fabs(jstrafe[2]), 0.00092);
jstrafe[2] *= mag;
if (joy_radialdeadzone.ival)
{
mag = joydeadzone(sqrt(jlook[0]*jlook[0] + jlook[1]*jlook[1]), sqrt(joy_anglethreshold[0].value*joy_anglethreshold[0].value + joy_anglethreshold[1].value*joy_anglethreshold[1].value));
mag = pow(mag, joy_exponent.value);
jlook[0] *= mag;
jlook[1] *= mag;
mag = joydeadzone(fabs(jlook[2]), joy_anglethreshold[2].value);
jlook[2] *= mag;
mag = joydeadzone(sqrt(jstrafe[0]*jstrafe[0] + jstrafe[1]*jstrafe[1]), sqrt(joy_movethreshold[0].value*joy_movethreshold[0].value + joy_movethreshold[1].value*joy_movethreshold[1].value));
mag = pow(mag, joy_exponent.value);
jstrafe[0] *= mag;
jstrafe[1] *= mag;
mag = joydeadzone(fabs(jstrafe[2]), joy_movethreshold[2].value);
jstrafe[2] *= mag;
}
else
{
for (i = 0; i < 3; i++)
{
mag = joydeadzone(fabs(jlook[i]), joy_anglethreshold[i].value);
mag = pow(mag, joy_exponent.value);
jlook[i] *= mag;
mag = joydeadzone(fabs(jstrafe[i]), joy_movethreshold[i].value);
mag = pow(mag, joy_exponent.value);
jstrafe[i] *= mag;
}
}
if (Key_Dest_Has(~kdm_game))
{
@ -635,24 +766,28 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet
VectorClear(jstrafe);
}
VectorScale(jlook, frametime, jlook);
VectorScale(jstrafe, frametime, jstrafe);
if (in_speed.state[pnum] & 1)
{
VectorScale(jlook, 360*cl_movespeedkey.value, jlook);
VectorScale(jstrafe, 360*cl_movespeedkey.value, jstrafe);
}
VectorScale(jlook, 360*frametime, jlook);
if (!movements) //if this is null, gamecode should still get inputs, just no camera looking or anything.
return;
//angle changes
cl.playerview[pnum].viewanglechange[YAW] -= m_yaw.value * jlook[0];
cl.playerview[pnum].viewanglechange[PITCH] += m_pitch.value * jlook[1];
// cl.playerview[pnum].viewanglechange[ROLL] += m_roll.value * jlook[2]; //this would be too weird.
cl.playerview[pnum].viewanglechange[PITCH] += joy_anglesens[0].value * jlook[0];
cl.playerview[pnum].viewanglechange[YAW] += joy_anglesens[1].value * jlook[1];
cl.playerview[pnum].viewanglechange[ROLL] += joy_anglesens[2].value * jlook[2];
if (in_mlook.state[pnum] & 1)
V_StopPitchDrift (&cl.playerview[pnum]);
//movement
movements[1] += m_side.value * jstrafe[0]; //x=right=1
movements[0] -= m_forward.value * jstrafe[1]; //y=forward=0
movements[2] += m_side.value * jstrafe[2]; //z=up=2
movements[0] -= joy_movesens[0].value * cl_forwardspeed.value * jstrafe[0];
movements[1] -= joy_movesens[1].value * cl_sidespeed.value * jstrafe[1];
movements[2] -= joy_movesens[2].value * cl_upspeed.value * jstrafe[2];
}
void IN_Move (float *movements, int pnum, float frametime)

View File

@ -32,6 +32,49 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
void INS_Accumulate (void);
#define AVAIL_XINPUT
#ifdef AVAIL_XINPUT
//#define AVAIL_XINPUT_DLL "xinput9_1_0.dll"
#define AVAIL_XINPUT_DLL "xinput1_3.dll"
typedef struct _XINPUT_GAMEPAD {
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
typedef struct _XINPUT_STATE {
DWORD dwPacketNumber;
XINPUT_GAMEPAD Gamepad;
} XINPUT_STATE, *PXINPUT_STATE;
typedef struct _XINPUT_VIBRATION {
WORD wLeftMotorSpeed;
WORD wRightMotorSpeed;
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
DWORD (WINAPI *pXInputGetState)(DWORD dwUserIndex, XINPUT_STATE *pState);
DWORD (WINAPI *pXInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION *pState);
enum
{
XINPUT_GAMEPAD_DPAD_UP = 0x0001,
XINPUT_GAMEPAD_DPAD_DOWN = 0x0002,
XINPUT_GAMEPAD_DPAD_LEFT = 0x0004,
XINPUT_GAMEPAD_DPAD_RIGHT = 0x0008,
XINPUT_GAMEPAD_START = 0x0010,
XINPUT_GAMEPAD_BACK = 0x0020,
XINPUT_GAMEPAD_LEFT_THUMB = 0x0040,
XINPUT_GAMEPAD_RIGHT_THUMB = 0x0080,
XINPUT_GAMEPAD_LEFT_SHOULDER = 0x0100,
XINPUT_GAMEPAD_RIGHT_SHOULDER = 0x0200,
XINPUT_GAMEPAD_A = 0x1000,
XINPUT_GAMEPAD_B = 0x2000,
XINPUT_GAMEPAD_X = 0x4000,
XINPUT_GAMEPAD_Y = 0x8000
};
#endif
#ifdef AVAIL_DINPUT
#ifndef _MSC_VER
@ -53,10 +96,14 @@ HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion,
// mouse variables
static cvar_t in_dinput = CVARF("in_dinput","0", CVAR_ARCHIVE);
static cvar_t in_xinput = CVARFD("in_xinput","0", CVAR_ARCHIVE, "Enables the use of xinput for controllers.\nNote that if you have a headset plugged in, that headset will be used for audio playback if no specific audio device is configured (may require snd_restart too).");
static cvar_t in_builtinkeymap = CVARF("in_builtinkeymap", "0", CVAR_ARCHIVE);
static cvar_t in_simulatemultitouch = CVAR("in_simulatemultitouch", "0");
static cvar_t in_nonstandarddeadkeys = CVARD("in_nonstandarddeadkeys", "1", "Discard input events that result in multiple keys. Only the last key will be used. This results in behaviour that differs from eg notepad. To use a dead key, press it twice instead of the dead key followed by space.");
static cvar_t xinput_leftvibrator = CVARFD("xinput_leftvibrator","0", CVAR_ARCHIVE, "");
static cvar_t xinput_rightvibrator = CVARFD("xinput_rightvibrator","0", CVAR_ARCHIVE, "Enables the use of xinput for controllers.\nNote that if you have a headset plugged in, that headset will be used for audio playback if no specific audio device is configured (may require snd_restart too).");
static cvar_t m_accel_noforce = CVAR("m_accel_noforce", "0");
static cvar_t m_threshold_noforce = CVAR("m_threshold_noforce", "0");
@ -102,25 +149,7 @@ qboolean mouseactive;
#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick
#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball
#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V
#define JOY_AXIS_X 0
#define JOY_AXIS_Y 1
#define JOY_AXIS_Z 2
#define JOY_AXIS_R 3
#define JOY_AXIS_U 4
#define JOY_AXIS_V 5
enum _ControlList
{
AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn
};
static DWORD dwAxisFlags[JOY_MAX_AXES] =
{
JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
};
static DWORD dwAxisMap[JOY_MAX_AXES];
static DWORD dwControlMap[JOY_MAX_AXES];
// none of these cvars are saved over a session
// this means that advanced controller configuration needs to be executed
@ -128,30 +157,12 @@ static DWORD dwControlMap[JOY_MAX_AXES];
// or when changing from one controller to another. this way at least something
// works.
static cvar_t in_joystick = CVARF("joystick","0", CVAR_ARCHIVE);
static cvar_t joy_name = CVAR("joyname", "joystick");
static cvar_t joy_advanced = CVAR("joyadvanced", "0");
static cvar_t joy_advaxisx = CVAR("joyadvaxisx", "0");
static cvar_t joy_advaxisy = CVAR("joyadvaxisy", "0");
static cvar_t joy_advaxisz = CVAR("joyadvaxisz", "0");
static cvar_t joy_advaxisr = CVAR("joyadvaxisr", "0");
static cvar_t joy_advaxisu = CVAR("joyadvaxisu", "0");
static cvar_t joy_advaxisv = CVAR("joyadvaxisv", "0");
static cvar_t joy_forwardthreshold = CVAR("joyforwardthreshold", "0.15");
static cvar_t joy_sidethreshold = CVAR("joysidethreshold", "0.15");
static cvar_t joy_pitchthreshold = CVAR("joypitchthreshold", "0.15");
static cvar_t joy_yawthreshold = CVAR("joyyawthreshold", "0.15");
static cvar_t joy_forwardsensitivity = CVAR("joyforwardsensitivity", "-1.0");
static cvar_t joy_sidesensitivity = CVAR("joysidesensitivity", "-1.0");
static cvar_t joy_pitchsensitivity = CVAR("joypitchsensitivity", "1.0");
static cvar_t joy_yawsensitivity = CVAR("joyyawsensitivity", "-1.0");
static cvar_t joy_wwhack1 = CVAR("joywwhack1", "0.0");
static cvar_t joy_wwhack2 = CVAR("joywwhack2", "0.0");
static qboolean joy_advancedinit;
static DWORD joy_flags;
#define MAX_JOYSTICKS 4
#define MAX_JOYSTICKS 8
static struct wjoy_s {
qboolean isxinput; //xinput device
unsigned int id; //windows id. device id is the index.
unsigned int devid; //quake id (generally player index)
DWORD numbuttons;
@ -160,8 +171,6 @@ static struct wjoy_s {
DWORD oldpovstate;
DWORD buttonstate;
DWORD oldbuttonstate;
DWORD axis[JOY_MAX_AXES];
} wjoy[MAX_JOYSTICKS];
static int joy_count;
@ -285,7 +294,6 @@ void INS_RawInput_DeInit(void);
// forward-referenced functions
void INS_StartupJoystick (void);
void Joy_AdvancedUpdate_f (void);
void INS_JoyMove (float *movements, int pnum);
/*
@ -538,7 +546,7 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
if (activeapp)
{
if (!SCR_HardwareCursorIsActive() && (fullscreen || in_simulatemultitouch.ival || _windowed_mouse.value) && (current_mouse_pos.x >= window_rect.left && current_mouse_pos.y >= window_rect.top && current_mouse_pos.x <= window_rect.right && current_mouse_pos.y <= window_rect.bottom))
if (!SCR_HardwareCursorIsActive() && (fullscreen || in_simulatemultitouch.ival || _windowed_mouse.value) && (fullscreen || (current_mouse_pos.x >= window_rect.left && current_mouse_pos.y >= window_rect.top && current_mouse_pos.x <= window_rect.right && current_mouse_pos.y <= window_rect.bottom)))
{
INS_HideMouse();
}
@ -1115,7 +1123,14 @@ void INS_Init (void)
//keyboard variables
Cvar_Register (&cl_keypad, "Input Controls");
#ifdef AVAIL_DINPUT
Cvar_Register (&in_dinput, "Input Controls");
#endif
#ifdef AVAIL_XINPUT
Cvar_Register (&in_xinput, "Input Controls");
Cvar_Register (&xinput_leftvibrator, "Input Controls");
Cvar_Register (&xinput_rightvibrator, "Input Controls");
#endif
Cvar_Register (&in_builtinkeymap, "Input Controls");
Cvar_Register (&in_nonstandarddeadkeys, "Input Controls");
Cvar_Register (&in_simulatemultitouch, "Input Controls");
@ -1143,27 +1158,7 @@ void INS_Init (void)
// joystick variables
Cvar_Register (&in_joystick, "Joystick variables");
Cvar_Register (&joy_name, "Joystick variables");
Cvar_Register (&joy_advanced, "Joystick variables");
Cvar_Register (&joy_advaxisx, "Joystick variables");
Cvar_Register (&joy_advaxisy, "Joystick variables");
Cvar_Register (&joy_advaxisz, "Joystick variables");
Cvar_Register (&joy_advaxisr, "Joystick variables");
Cvar_Register (&joy_advaxisu, "Joystick variables");
Cvar_Register (&joy_advaxisv, "Joystick variables");
Cvar_Register (&joy_forwardthreshold, "Joystick variables");
Cvar_Register (&joy_sidethreshold, "Joystick variables");
Cvar_Register (&joy_pitchthreshold, "Joystick variables");
Cvar_Register (&joy_yawthreshold, "Joystick variables");
Cvar_Register (&joy_forwardsensitivity, "Joystick variables");
Cvar_Register (&joy_sidesensitivity, "Joystick variables");
Cvar_Register (&joy_pitchsensitivity, "Joystick variables");
Cvar_Register (&joy_yawsensitivity, "Joystick variables");
Cvar_Register (&joy_wwhack1, "Joystick variables");
Cvar_Register (&joy_wwhack2, "Joystick variables");
Cmd_AddCommand ("force_centerview", Force_CenterView_f);
Cmd_AddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f);
uiWheelMessage = RegisterWindowMessageA ( "MSWHEEL_ROLLMSG" );
@ -1590,6 +1585,46 @@ static void INS_StartupJoystickId(unsigned int id)
joy_count++;
}
void INS_SetupControllerAudioDevices(void)
{
#ifdef AVAIL_XINPUT
int i;
static DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid);
static dllhandle_t *xinput;
if (!xinput)
{
dllfunction_t funcs[] =
{
{(void**)&pXInputGetDSoundAudioDeviceGuids, "XInputGetDSoundAudioDeviceGuids"},
{NULL}
};
xinput = Sys_LoadLibrary(AVAIL_XINPUT_DLL, funcs);
}
if (!pXInputGetDSoundAudioDeviceGuids)
return;
for (i = 0; i < joy_count; i++)
{
char audiodevicename[MAX_QPATH];
wchar_t mssuck[MAX_QPATH];
GUID gplayback = GUID_NULL;
GUID gcapture = GUID_NULL;
if (!wjoy[i].isxinput)
continue;
if (pXInputGetDSoundAudioDeviceGuids(wjoy[i].id, &gplayback, &gcapture) != ERROR_SUCCESS)
continue; //probably not plugged in
if (!memcmp(&gplayback, &GUID_NULL, sizeof(gplayback)))
continue; //we have a controller, but no headset.
StringFromGUID2(&gplayback, mssuck, sizeof(mssuck)/sizeof(mssuck[0]));
narrowen(audiodevicename, sizeof(audiodevicename), mssuck);
Con_Printf("Controller %i uses audio device %s\n", wjoy[i].id, audiodevicename);
S_SetupDeviceSeat("DirectSound", audiodevicename, wjoy[i].devid);
}
#endif
}
void INS_StartupJoystick (void)
{
unsigned int id, numdevs;
@ -1598,8 +1633,45 @@ void INS_StartupJoystick (void)
// assume no joysticks
joy_count = 0;
#ifdef AVAIL_XINPUT
if (in_xinput.ival)
{
static dllhandle_t *xinput;
if (!xinput)
{
dllfunction_t funcs[] =
{
{(void**)&pXInputGetState, "XInputGetState"},
{(void**)&pXInputSetState, "XInputSetState"},
{NULL}
};
xinput = Sys_LoadLibrary(AVAIL_XINPUT_DLL, funcs);
}
if (pXInputGetState)
{
DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid);
pXInputGetDSoundAudioDeviceGuids = Sys_GetAddressForName(xinput, "XInputGetDSoundAudioDeviceGuids");
for (id = 0; id < 4; id++)
{
if (joy_count == countof(wjoy))
break;
memset(&wjoy[id], 0, sizeof(wjoy[id]));
wjoy[joy_count].isxinput = true;
wjoy[joy_count].id = id;
wjoy[joy_count].devid = id;
wjoy[joy_count].numbuttons = 16;
joy_count++;
}
Con_Printf("XInput is enabled (max %i controllers)\n", id);
}
else
Con_Printf("XInput not installed\n");
}
#endif
// abort startup if user requests no joystick
if ( COM_CheckParm ("-nojoy") )
if (!in_joystick.ival )
return;
// verify joystick driver is present
@ -1630,77 +1702,6 @@ void INS_StartupJoystick (void)
Con_DPrintf ("found no joysticks\n");
}
/*
===========
Joy_AdvancedUpdate_f
===========
*/
void Joy_AdvancedUpdate_f (void)
{
// called once by INS_ReadJoystick and by user whenever an update is needed
// cvars are now available
int i;
DWORD dwTemp;
// initialize all the maps
for (i = 0; i < JOY_MAX_AXES; i++)
{
dwAxisMap[i] = AxisNada;
dwControlMap[i] = JOY_ABSOLUTE_AXIS;
}
if( joy_advanced.value == 0.0)
{
// default joystick initialization
// 2 axes only with joystick control
dwAxisMap[JOY_AXIS_X] = AxisTurn;
// dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
dwAxisMap[JOY_AXIS_Y] = AxisForward;
// dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
}
else
{
if (Q_strcmp (joy_name.string, "joystick") != 0)
{
// notify user of advanced controller
Con_Printf ("\n%s configured\n\n", joy_name.string);
}
// advanced initialization here
// data supplied by user via joy_axisn cvars
dwTemp = (DWORD) joy_advaxisx.value;
dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisy.value;
dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisz.value;
dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisr.value;
dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisu.value;
dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisv.value;
dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
}
// compute the axes to collect from DirectInput
joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
for (i = 0; i < JOY_MAX_AXES; i++)
{
if (dwAxisMap[i] != AxisNada)
{
joy_flags |= dwAxisFlags[i];
}
}
}
/*
===========
INS_Commands
@ -1708,11 +1709,67 @@ INS_Commands
*/
void INS_Commands (void)
{
int i, key_index;
int i;
DWORD buttonstate, povstate;
unsigned int idx;
struct wjoy_s *joy;
static const int xinputjbuttons[] =
{
K_UPARROW, //XINPUT_GAMEPAD_DPAD_UP
K_DOWNARROW, //XINPUT_GAMEPAD_DPAD_DOWN
K_LEFTARROW, //XINPUT_GAMEPAD_DPAD_LEFT
K_RIGHTARROW, //XINPUT_GAMEPAD_DPAD_RIGHT
K_AUX5, //XINPUT_GAMEPAD_START
K_AUX6, //XINPUT_GAMEPAD_BACK
K_AUX3, //XINPUT_GAMEPAD_LEFT_THUMB
K_AUX4, //XINPUT_GAMEPAD_RIGHT_THUMB
K_AUX1, //XINPUT_GAMEPAD_LEFT_SHOULDER
K_AUX2, //XINPUT_GAMEPAD_RIGHT_SHOULDER
K_JOY2, //XINPUT_GAMEPAD_A
K_JOY4, //XINPUT_GAMEPAD_B
K_JOY1, //XINPUT_GAMEPAD_X
K_JOY3 //XINPUT_GAMEPAD_Y
};
static const int dinputjbuttons[32] =
{
K_JOY1,
K_JOY2,
K_JOY3,
K_JOY4,
//yes, aux1-4 skipped for compat with other quake engines.
K_AUX5,
K_AUX6,
K_AUX7,
K_AUX8,
K_AUX9,
K_AUX10,
K_AUX11,
K_AUX12,
K_AUX13,
K_AUX14,
K_AUX15,
K_AUX16,
K_AUX17,
K_AUX18,
K_AUX19,
K_AUX20,
K_AUX21,
K_AUX22,
K_AUX23,
K_AUX24,
K_AUX25,
K_AUX26,
K_AUX27,
K_AUX28,
//29-32 used for the pov stuff, so lets switch back to aux1-4 to avoid wastage
K_AUX1,
K_AUX2,
K_AUX3,
K_AUX4
};
for (idx = 0; idx < joy_count; idx++)
{
joy = &wjoy[idx];
@ -1720,18 +1777,26 @@ void INS_Commands (void)
// loop through the joystick buttons
// key a joystick event or auxillary event for higher number buttons for each state change
buttonstate = joy->buttonstate;
for (i=0 ; i < joy->numbuttons ; i++)
if (joy->isxinput)
{
if ( (buttonstate & (1<<i)) && !(joy->oldbuttonstate & (1<<i)) )
for (i=0 ; i < joy->numbuttons ; i++)
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event (joy->devid, key_index + i, 0, true);
}
if ( (buttonstate & (1<<i)) && !(joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, xinputjbuttons[i], 0, true);
if ( !(buttonstate & (1<<i)) && (joy->oldbuttonstate & (1<<i)) )
if ( !(buttonstate & (1<<i)) && (joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, xinputjbuttons[i], 0, false);
}
}
else
{
for (i=0 ; i < joy->numbuttons ; i++)
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event (joy->devid, key_index + i, 0, false);
if ( (buttonstate & (1<<i)) && !(joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, dinputjbuttons[i], 0, true);
if ( !(buttonstate & (1<<i)) && (joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, dinputjbuttons[i], 0, false);
}
}
joy->oldbuttonstate = buttonstate;
@ -1779,54 +1844,88 @@ INS_ReadJoystick
*/
qboolean INS_ReadJoystick (struct wjoy_s *joy)
{
memset (&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji);
ji.dwFlags = joy_flags;
if (joyGetPosEx (joy->id, &ji) == JOYERR_NOERROR)
#ifdef AVAIL_XINPUT
if (joy->isxinput)
{
// this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
// rather than having 32768 be the zero point, they have the zero point at 32668
// go figure -- anyway, now we get the full resolution out of the device
if (joy_wwhack1.value != 0.0)
XINPUT_STATE xistate;
XINPUT_VIBRATION vibrator;
HRESULT hr = pXInputGetState(joy->id, &xistate);
#if 1
//I don't have a controller to test this with, so we fake stuff.
if (joy->id == 3)
{
ji.dwUpos += 100;
POINT p;
GetCursorPos(&p);
hr = ERROR_SUCCESS;
xistate.Gamepad.wButtons = 0;
xistate.Gamepad.sThumbRX = 0;//(p.x/1920.0)*0xffff - 0x8000;
xistate.Gamepad.sThumbRY = 0;//(p.y/1080.0)*0xffff - 0x8000;
xistate.Gamepad.sThumbLX = (p.x/1920.0)*0xffff - 0x8000;
xistate.Gamepad.sThumbLY = (p.y/1080.0)*0xffff - 0x8000;
xistate.Gamepad.bLeftTrigger = 0;
xistate.Gamepad.bRightTrigger = 0;
}
#endif
if (hr == ERROR_SUCCESS)
{ //ERROR_SUCCESS
//do we care about the dwPacketNumber?
joy->buttonstate = xistate.Gamepad.wButtons & 0xffff;
IN_JoystickAxisEvent(joy->devid, 0, xistate.Gamepad.sThumbRX / 32768.0);
IN_JoystickAxisEvent(joy->devid, 1, xistate.Gamepad.sThumbRY / 32768.0);
IN_JoystickAxisEvent(joy->devid, 2, xistate.Gamepad.bRightTrigger/255.0);
IN_JoystickAxisEvent(joy->devid, 3, xistate.Gamepad.sThumbLX / 32768.0);
IN_JoystickAxisEvent(joy->devid, 4, xistate.Gamepad.sThumbLY / 32768.0);
IN_JoystickAxisEvent(joy->devid, 5, xistate.Gamepad.bLeftTrigger/255.0);
vibrator.wLeftMotorSpeed = xinput_leftvibrator.value * 0xffff;
vibrator.wRightMotorSpeed = xinput_rightvibrator.value * 0xffff;
pXInputSetState(joy->id, &vibrator);
return true;
}
joy->povstate = ji.dwPOV;
joy->buttonstate = ji.dwButtons;
joy->axis[JOY_AXIS_X] = ji.dwXpos;
joy->axis[JOY_AXIS_Y] = ji.dwYpos;
joy->axis[JOY_AXIS_Z] = ji.dwZpos;
joy->axis[JOY_AXIS_R] = ji.dwRpos;
joy->axis[JOY_AXIS_U] = ji.dwUpos;
joy->axis[JOY_AXIS_V] = ji.dwVpos;
return true;
}
else
#endif
{
joy->povstate = 0;
joy->buttonstate = 0;
joy->axis[JOY_AXIS_X] = 32768;
joy->axis[JOY_AXIS_Y] = 32768;
joy->axis[JOY_AXIS_Z] = 32768;
joy->axis[JOY_AXIS_R] = 32768;
joy->axis[JOY_AXIS_U] = 32768;
joy->axis[JOY_AXIS_V] = 32768;
memset (&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji);
ji.dwFlags = joy_flags;
// read error occurred
// turning off the joystick seems too harsh for 1 read error,
// but what should be done?
// Con_Printf ("INS_ReadJoystick: no response\n");
// joy_avail = false;
return false;
if (joyGetPosEx (joy->id, &ji) == JOYERR_NOERROR)
{
joy->povstate = ji.dwPOV;
joy->buttonstate = ji.dwButtons;
IN_JoystickAxisEvent(joy->devid, 0, (ji.dwXpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 1, (ji.dwYpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 2, (ji.dwZpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 3, (ji.dwRpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 4, (ji.dwUpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 5, (ji.dwVpos - 32768.0) / 32768);
return true;
}
}
joy->povstate = 0;
joy->buttonstate = 0;
IN_JoystickAxisEvent(joy->devid, 0, 0);
IN_JoystickAxisEvent(joy->devid, 1, 0);
IN_JoystickAxisEvent(joy->devid, 2, 0);
IN_JoystickAxisEvent(joy->devid, 3, 0);
IN_JoystickAxisEvent(joy->devid, 4, 0);
IN_JoystickAxisEvent(joy->devid, 5, 0);
// read error occurred
// turning off the joystick seems too harsh for 1 read error,
// but what should be done?
// Con_Printf ("INS_ReadJoystick: no response\n");
// joy_avail = false;
return false;
}
static void INS_JoyMovePtr (struct wjoy_s *joy, float *movements, int pnum)
{
float speed, aspeed;
float fAxisValue, fTemp;
int i;
int wpnum;
/*each device will be processed when its player comes to be processed*/
@ -1846,153 +1945,6 @@ static void INS_JoyMovePtr (struct wjoy_s *joy, float *movements, int pnum)
{
return;
}
if (in_speed.state[pnum] & 1)
speed = cl_movespeedkey.value;
else
speed = 1;
aspeed = speed * host_frametime;
// loop through the axes
for (i = 0; i < JOY_MAX_AXES; i++)
{
// get the floating point zero-centered, potentially-inverted data for the current axis
fAxisValue = (float) joy->axis[i];
// move centerpoint to zero
fAxisValue -= 32768.0;
if (joy_wwhack2.value != 0.0)
{
if (dwAxisMap[i] == AxisTurn)
{
// this is a special formula for the Logitech WingMan Warrior
// y=ax^b; where a = 300 and b = 1.3
// also x values are in increments of 800 (so this is factored out)
// then bounds check result to level out excessively high spin rates
fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3);
if (fTemp > 14000.0)
fTemp = 14000.0;
// restore direction information
fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp;
}
}
// convert range from -32768..32767 to -1..1
fAxisValue /= 32768.0;
#ifdef CSQC_DAT
if (CSQC_JoystickAxis(i, fAxisValue, joy->devid))
continue;
#endif
switch (dwAxisMap[i])
{
case AxisForward:
if ((joy_advanced.value == 0.0) && (in_mlook.state[pnum] & 1))
{
// user wants forward control to become look control
if (fabs(fAxisValue) > joy_pitchthreshold.value)
{
// if mouse invert is on, invert the joystick pitch value
// only absolute control support here (joy_advanced is false)
if (m_pitch.value < 0.0)
{
cl.playerview[pnum].viewanglechange[PITCH] -= (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
}
else
{
cl.playerview[pnum].viewanglechange[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
}
V_StopPitchDrift(&cl.playerview[pnum]);
}
else
{
// no pitch movement
// disable pitch return-to-center unless requested by user
// *** this code can be removed when the lookspring bug is fixed
// *** the bug always has the lookspring feature on
if(lookspring.value == 0.0)
V_StopPitchDrift(&cl.playerview[pnum]);
}
}
else
{
// user wants forward control to be forward control
if (fabs(fAxisValue) > joy_forwardthreshold.value)
{
movements[0] += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value;
}
}
break;
case AxisSide:
if (fabs(fAxisValue) > joy_sidethreshold.value)
{
movements[1] += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
}
break;
case AxisTurn:
if ((in_strafe.state[pnum] & 1) || (lookstrafe.value && (in_mlook.state[pnum] & 1)))
{
// user wants turn control to become side control
if (fabs(fAxisValue) > joy_sidethreshold.value)
{
movements[2] -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
}
}
else
{
// user wants turn control to be turn control
if (fabs(fAxisValue) > joy_yawthreshold.value)
{
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
{
cl.playerview[pnum].viewanglechange[YAW] += (fAxisValue * joy_yawsensitivity.value) * aspeed * cl_yawspeed.value;
}
else
{
cl.playerview[pnum].viewanglechange[YAW] += (fAxisValue * joy_yawsensitivity.value) * speed * 180.0;
}
}
}
break;
case AxisLook:
if (in_mlook.state[pnum] & 1)
{
if (fabs(fAxisValue) > joy_pitchthreshold.value)
{
// pitch movement detected and pitch movement desired by user
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
{
cl.playerview[pnum].viewanglechange[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
}
else
{
cl.playerview[pnum].viewanglechange[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0;
}
V_StopPitchDrift(&cl.playerview[pnum]);
}
else
{
// no pitch movement
// disable pitch return-to-center unless requested by user
// *** this code can be removed when the lookspring bug is fixed
// *** the bug always has the lookspring feature on
if(lookspring.value == 0.0)
V_StopPitchDrift(&cl.playerview[pnum]);
}
}
break;
default:
break;
}
}
CL_ClampPitch(pnum);
}
/*
===========
@ -2002,19 +1954,6 @@ INS_JoyMove
void INS_JoyMove (float *movements, int pnum)
{
unsigned int idx;
// complete initialization if first time in
// this is needed as cvars are not available at initialization time
if( joy_advancedinit != true )
{
Joy_AdvancedUpdate_f();
joy_advancedinit = true;
}
// verify joystick is available and that the user wants to use it
if (!in_joystick.value)
return;
for (idx = 0; idx < joy_count; idx++)
{
INS_JoyMovePtr(&wjoy[idx], movements, pnum);
@ -2040,7 +1979,12 @@ void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char
callback(ctx, "mouse", "system", NULL);
for (idx = 0; idx < joy_count; idx++)
callback(ctx, "joy", va("mmj%i", idx), &wjoy[idx].devid);
{
if (wjoy[idx].isxinput)
callback(ctx, "joy", va("xi%i", wjoy[idx].id), &wjoy[idx].devid);
else
callback(ctx, "joy", va("mmj%i", wjoy[idx].id), &wjoy[idx].devid);
}
}
static qbyte scantokey[] =

View File

@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
void IN_ReInit (void);
void IN_Init (void);
float IN_DetermineMouseRate(void);
void IN_Shutdown (void);
@ -58,6 +59,7 @@ void INS_Init (void);
void INS_Shutdown (void);
void INS_Commands (void); //final chance to call IN_MouseMove/IN_KeyEvent each frame
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid));
void INS_SetupControllerAudioDevices(void); //creates audio devices for each controller (where controllers have their own audio devices)
extern cvar_t cl_nodelta;
extern cvar_t cl_c2spps;

View File

@ -46,6 +46,7 @@ struct key_cursor_s key_customcursor[kc_max];
int key_count; // incremented every key event
int key_bindmaps[2];
char *keybindings[K_MAX][KEY_MODIFIERSTATES];
qbyte bindcmdlevel[K_MAX][KEY_MODIFIERSTATES];
qboolean consolekeys[K_MAX]; // if true, can't be rebound while in console
@ -79,6 +80,30 @@ static int KeyModifier (qboolean shift, qboolean alt, qboolean ctrl)
return stateset;
}
void Key_GetBindMap(int *bindmaps)
{
int i;
for (i = 0; i < countof(key_bindmaps); i++)
{
if (key_bindmaps[i])
bindmaps[i] = (key_bindmaps[i]&~KEY_MODIFIER_ALTBINDMAP) + 1;
else
bindmaps[i] = 0;
}
}
void Key_SetBindMap(int *bindmaps)
{
int i;
for (i = 0; i < countof(key_bindmaps); i++)
{
if (bindmaps[i] > 0 && bindmaps[i] <= KEY_MODIFIER_ALTBINDMAP)
key_bindmaps[i] = (bindmaps[i]-1)|KEY_MODIFIER_ALTBINDMAP;
else
key_bindmaps[i] = 0;
}
}
typedef struct
{
char *name;
@ -227,6 +252,7 @@ keyname_t keynames[] =
{"SCROLLLOCK", K_SCRLCK},
{"SEMICOLON", ';'}, // because a raw semicolon seperates commands
{"PLUS", '+'}, // because "shift++" is inferior to shift+plus
{"TILDE", '~'},
{"BACKQUOTE", '`'},
@ -1543,11 +1569,28 @@ void Key_Message (int key, int unicode)
//============================================================================
char *Key_GetBinding(int keynum)
//for qc
char *Key_GetBinding(int keynum, int bindmap, int modifier)
{
if (keynum >= 0 && keynum < K_MAX)
return keybindings[keynum][0];
return NULL;
char *key = NULL;
if (keynum < 0 || keynum >= K_MAX)
;
else if (bindmap < 0)
{
key = NULL;
if (!key)
key = keybindings[keynum][key_bindmaps[0]];
if (!key)
key = keybindings[keynum][key_bindmaps[1]];
}
else
{
if (bindmap)
modifier = (bindmap-1) + KEY_MODIFIER_ALTBINDMAP;
if (modifier >= 0 && modifier < KEY_MODIFIERSTATES)
key = keybindings[keynum][modifier];
}
return key;
}
/*
@ -1562,27 +1605,36 @@ the K_* names are matched up.
int Key_StringToKeynum (const char *str, int *modifier)
{
keyname_t *kn;
char *underscore;
if (!strnicmp(str, "std_", 4))
if (!strnicmp(str, "std_", 4) || !strnicmp(str, "std+", 4))
*modifier = 0;
else
{
*modifier = 0;
while(1)
struct
{
underscore = strchr(str, '_');
if (!underscore || !underscore[1])
break; //nothing afterwards or no underscore.
if (!strnicmp(str, "shift_", 6))
*modifier |= KEY_MODIFIER_SHIFT;
else if (!strnicmp(str, "alt_", 4))
*modifier |= KEY_MODIFIER_ALT;
else if (!strnicmp(str, "ctrl_", 5))
*modifier |= KEY_MODIFIER_CTRL;
else
break;
str = underscore+1; //next char.
char *prefix;
int len;
int mod;
} mods[] =
{
{"shift", 5, KEY_MODIFIER_SHIFT},
{"ctrl", 4, KEY_MODIFIER_CTRL},
{"alt", 3, KEY_MODIFIER_ALT},
};
int i;
*modifier = 0;
for (i = 0; i < countof(mods); )
{
if (!Q_strncasecmp(mods[i].prefix, str, mods[i].len))
if (str[mods[i].len] == '_' || str[mods[i].len] == '+' || str[mods[i].len] == ' ')
if (str[mods[i].len+1])
{
*modifier |= mods[i].mod;
str += mods[i].len+1;
i = 0;
continue;
}
i++;
}
if (!*modifier)
*modifier = ~0;
@ -1623,7 +1675,7 @@ given keynum.
FIXME: handle quote special (general escape sequence?)
===================
*/
char *Key_KeynumToString (int keynum)
static char *Key_KeynumToStringRaw (int keynum)
{
keyname_t *kn;
static char tinystr[2];
@ -1650,6 +1702,31 @@ char *Key_KeynumToString (int keynum)
return "<UNKNOWN KEYNUM>";
}
char *Key_KeynumToString (int keynum, int modifier)
{
char *r = Key_KeynumToStringRaw(keynum);
if (r[0] == '<' && r[1])
modifier = 0; //would be too weird.
switch(modifier)
{
case KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT:
return va("Ctrl+Alt+Shift+%s", r);
case KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT:
return va("Alt+Shift+%s", r);
case KEY_MODIFIER_CTRL|KEY_MODIFIER_SHIFT:
return va("Ctrl+Shift+%s", r);
case KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT:
return va("Ctrl+Alt+%s", r);
case KEY_MODIFIER_CTRL:
return va("Ctrl+%s", r);
case KEY_MODIFIER_ALT:
return va("Alt+%s", r);
case KEY_MODIFIER_SHIFT:
return va("Shift+%s", r);
default:
return r;
}
}
/*
===================
@ -1663,8 +1740,16 @@ void Key_SetBinding (int keynum, int modifier, char *binding, int level)
if (modifier == ~0) //all of the possibilities.
{
for (l = 0; l < KEY_MODIFIERSTATES; l++)
Key_SetBinding(keynum, l, binding, level);
if (binding)
{ //bindmaps are meant to be independant of each other.
for (l = 0; l < KEY_MODIFIER_ALTBINDMAP; l++)
Key_SetBinding(keynum, l, binding, level);
}
else
{ //when unbinding, unbind all bindmaps.
for (l = 0; l < KEY_MODIFIERSTATES; l++)
Key_SetBinding(keynum, l, binding, level);
}
return;
}
@ -1753,6 +1838,13 @@ void Key_Bind_f (void)
{
int i, c, b, modifier;
char cmd[1024];
int bindmap = 0;
if (!strcmp("in_bind", Cmd_Argv(0)))
{
bindmap = atoi(Cmd_Argv(1));
Cmd_ShiftArgs(1, Cmd_ExecLevel==RESTRICT_LOCAL);
}
c = Cmd_Argc();
@ -1768,6 +1860,20 @@ void Key_Bind_f (void)
Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
return;
}
if (bindmap)
{
if (bindmap < 0 || bindmap > KEY_MODIFIER_ALTBINDMAP)
{
Con_Printf ("unsupported bindmap %i\n", bindmap);
return;
}
if (modifier != ~0)
{
Con_Printf ("modifiers cannot be combined with bindmaps\n");
return;
}
modifier = (bindmap-1) | KEY_MODIFIER_ALTBINDMAP;
}
if (c == 2)
{
@ -1874,7 +1980,6 @@ void Key_WriteBindings (vfsfile_t *f)
int i, m;
char *binding, *base;
char prefix[128];
char keybuf[256];
char commandbuf[2048];
@ -1883,22 +1988,14 @@ void Key_WriteBindings (vfsfile_t *f)
base = keybindings[i][0]; //plus we can use the config with other clients.
if (!base)
base = "";
for (m = 0; m < KEY_MODIFIERSTATES; m++)
for (m = 0; m < KEY_MODIFIER_ALTBINDMAP; m++)
{
binding = keybindings[i][m];
if (!binding)
binding = "";
if (strcmp(binding, base) || (m==0 && keybindings[i][0]) || bindcmdlevel[i][m] != bindcmdlevel[i][0])
{
*prefix = '\0';
if (m & KEY_MODIFIER_CTRL)
strcat(prefix, "CTRL_");
if (m & KEY_MODIFIER_ALT)
strcat(prefix, "ALT_");
if (m & KEY_MODIFIER_SHIFT)
strcat(prefix, "SHIFT_");
s = va("%s%s", prefix, Key_KeynumToString(i));
s = Key_KeynumToString(i, m);
//quote it as required
if (i == ';' || i <= ' ' || i == '\"')
s = COM_QuotedString(s, keybuf, sizeof(keybuf), false);
@ -1910,6 +2007,21 @@ void Key_WriteBindings (vfsfile_t *f)
VFS_WRITE(f, s, strlen(s));
}
}
//now generate some special in_binds for bindmaps.
for (m = 0; m < KEY_MODIFIER_ALTBINDMAP; m++)
{
binding = keybindings[i][m|KEY_MODIFIER_ALTBINDMAP];
if (binding && *binding)
{
s = va("%s", Key_KeynumToString(i, 0));
//quote it as required
if (i == ';' || i <= ' ' || i == '\"')
s = COM_QuotedString(s, keybuf, sizeof(keybuf), false);
s = va("in_bind %i %s %s\n", m+1, s, COM_QuotedString(binding, commandbuf, sizeof(commandbuf), false));
VFS_WRITE(f, s, strlen(s));
}
}
}
}
@ -2012,6 +2124,7 @@ void Key_Init (void)
// register our functions
//
Cmd_AddCommand ("bind",Key_Bind_f);
Cmd_AddCommand ("in_bind",Key_Bind_f);
Cmd_AddCommand ("bindlevel",Key_BindLevel_f);
Cmd_AddCommand ("unbind",Key_Unbind_f);
Cmd_AddCommand ("unbindall",Key_Unbindall_f);
@ -2125,8 +2238,8 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
}
//yes, csqc is allowed to steal the escape key.
if (key != '`' && (!down || key != K_ESCAPE || (!Key_Dest_Has(~kdm_game) && !shift_down)))
if (!Key_Dest_Has(~kdm_game) && !Media_PlayingFullScreen())
if (key != '`' && (!down || key != K_ESCAPE || (!Key_Dest_Has(~kdm_game) && !shift_down)) &&
!Key_Dest_Has(~kdm_game) && !Media_PlayingFullScreen())
{
#ifdef CSQC_DAT
if (CSQC_KeyPress(key, unicode, down, devid)) //give csqc a chance to handle it.
@ -2135,6 +2248,13 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
#ifdef VM_CG
if (CG_KeyPress(key, unicode, down))
return;
#endif
}
else if (!down && key)
{
#ifdef CSQC_DAT
//csqc should still be told of up events. note that there's some filering to prevent notifying about events that it shouldn't receive (like all the up events when typing at the console).
CSQC_KeyPress(key, unicode, down, devid);
#endif
}
@ -2159,7 +2279,13 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
#endif
if (!down)
{
#ifdef MENU_DAT
if (Key_Dest_Has(kdm_gmenu) && !Key_Dest_Has(kdm_editor|kdm_console|kdm_cwindows))
MP_Keyup (key, unicode);
#endif
return;
}
if (Key_Dest_Has(kdm_console))
{
@ -2342,8 +2468,27 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
else
*p = 0;
dc = keybindings[key][modifierstate];
bl = bindcmdlevel[key][modifierstate];
//assume the worst
dc = NULL;
bl = 0;
//try bindmaps if they're set
if (key_bindmaps[0] && (!dc || !*dc))
{
dc = keybindings[key][key_bindmaps[0]];
bl = bindcmdlevel[key][key_bindmaps[0]];
}
if (key_bindmaps[1] && (!dc || !*dc))
{
dc = keybindings[key][key_bindmaps[1]];
bl = bindcmdlevel[key][key_bindmaps[1]];
}
//regular ctrl_alt_shift_foo binds
if (!dc || !*dc)
{
dc = keybindings[key][modifierstate];
bl = bindcmdlevel[key][modifierstate];
}
//simulate singular shift+alt+ctrl for binds (no left/right). really though, this code should translate to csqc/menu keycodes and back to resolve the weirdness instead.
if (key == K_RALT && (!dc || !*dc))

View File

@ -166,10 +166,11 @@ K_PRINTSCREEN = 248,
K_MAX = 256
};
#define KEY_MODIFIER_SHIFT (1<<0)
#define KEY_MODIFIER_ALT (1<<1)
#define KEY_MODIFIER_CTRL (1<<2)
#define KEY_MODIFIERSTATES (1<<3)
#define KEY_MODIFIER_SHIFT (1<<0)
#define KEY_MODIFIER_ALT (1<<1)
#define KEY_MODIFIER_CTRL (1<<2)
#define KEY_MODIFIER_ALTBINDMAP (1<<3)
#define KEY_MODIFIERSTATES (1<<4)
#define K_SHIFT K_LSHIFT
#define K_CTRL K_LCTRL
@ -194,7 +195,7 @@ typedef enum //highest has priority
extern unsigned int key_dest_absolutemouse; //if the active key dest bit is set, the mouse is absolute.
extern unsigned int key_dest_mask;
extern char *keybindings[K_MAX][8];
extern char *keybindings[K_MAX][16];
extern int key_repeats[K_MAX];
extern int key_count; // incremented every key event
extern int key_lastpress;

View File

@ -641,33 +641,32 @@ 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;
int keys[2];
int keys[8], keymods[countof(keys)];
int keycount;
char *keyname;
int j;
Draw_FunStringWidth(x, y, option->bind.caption, option->bind.captionwidth, true, !menu->cursoritem && menu->selecteditem == option);
x += option->bind.captionwidth + 3*8;
{
M_FindKeysForCommand (cl_forceseat.ival, option->bind.command, keys);
keycount = M_FindKeysForCommand (0, cl_forceseat.ival, option->bind.command, keys, keymods, countof(keys));
if (bindingactive && menu->selecteditem == option)
{
Draw_FunString (x, y, "Press key");
}
else if (keys[0] == -1)
{
Draw_FunString (x, y, "???");
}
else
{
keyname = Key_KeynumToString (keys[0]);
if (bindingactive && menu->selecteditem == option)
Draw_FunString (x, y, "Press key");
else if (!keycount)
Draw_FunString (x, y, "???");
else
{
for (j = 0; j < keycount; j++)
{ /*these offsets are wrong*/
if (j)
{
Draw_FunString (x + 8, y, "or");
x += 32;
}
keyname = Key_KeynumToString (keys[j], keymods[j]);
Draw_FunString (x, y, keyname);
x += strlen(keyname) * 8;
if (keys[1] != -1)
{ /*these offsets are wrong*/
Draw_FunString (x + 8, y, "or");
Draw_FunString (x + 32, y, Key_KeynumToString (keys[1]));
}
}
}
}
@ -1840,7 +1839,22 @@ void M_Complex_Key(int key, int unicode)
if (key != K_ESCAPE && key != '`')
{
Cbuf_InsertText (va("bind \"%s\" \"%s\"\n", Key_KeynumToString (key), currentmenu->selecteditem->bind.command), RESTRICT_LOCAL, false);
int modifiers = 0;
extern qboolean keydown[];
if (keydown[K_LSHIFT] && key != K_LSHIFT)
modifiers |= 1;
if (keydown[K_RSHIFT] && key != K_RSHIFT)
modifiers |= 1;
if (keydown[K_LALT] && key != K_LALT)
modifiers |= 2;
if (keydown[K_RALT] && key != K_RALT)
modifiers |= 2;
if (keydown[K_LCTRL] && key != K_LCTRL)
modifiers |= 4;
if (keydown[K_RCTRL] && key != K_RCTRL)
modifiers |= 4;
Cbuf_InsertText (va("bind \"%s\" \"%s\"\n", Key_KeynumToString (key, modifiers), currentmenu->selecteditem->bind.command), RESTRICT_LOCAL, false);
}
bindingactive = false;
return;

View File

@ -22,30 +22,68 @@ typedef struct mediatrack_s{
int length;
struct mediatrack_s *next;
} mediatrack_t;
qboolean media_fadeout;
float media_fadeouttime;
static mediatrack_t currenttrack;
int media_playing=true;//try to continue from the standard playlist
#endif
//higher bits have priority (if they have something to play).
#define MEDIA_GAMEMUSIC (1u<<0) //cd music. also music command etc.
#define MEDIA_CVARLIST (1u<<1) //cvar abuse. handy for preserving times when switching tracks.
#define MEDIA_PLAYLIST (1u<<2) //
static unsigned int media_playlisttypes;
//info about the current stuff that is playing.
static unsigned int media_playlistcurrent;
static char media_currenttrack[MAX_QPATH];
static char media_friendlyname[MAX_QPATH];
static int cdplayingtrack; //currently playing cd track (becomes 0 when paused)
static int cdpausedtrack; //currently paused cd track
//info about (fake)cd tracks that we want to play
int cdplaytracknum;
static char cdplaytrack[MAX_QPATH];
static char cdloopingtrack[MAX_QPATH];
static qboolean fakecdactive;
#define REMAPPED_TRACKS 100
//info about (fake)cd tracks that we could play if asked.
#define REMAPPED_TRACKS 256
static struct
{
char fname[MAX_QPATH];
} cdremap[REMAPPED_TRACKS];
static qboolean cdenabled;
static int cdplayingtrack; //currently playing cd track (becomes 0 when paused)
static int cdpausedtrack; //currently paused cd track
static int cdnumtracks; //maximum cd track we can play.
//flushes music channel on all soundcards, and the tracks that arn't decoded yet.
void Media_Clear (void)
//cvar abuse
static int music_playlist_last;
static cvar_t music_playlist_index = CVAR("music_playlist_index", "-1");
static cvar_t music_playlist_list[] =
{
CVAR("music_playlist_list0", ""),
CVAR("music_playlist_list1", ""),
CVAR("music_playlist_list2", ""),
CVAR("music_playlist_list3", ""),
CVAR("music_playlist_list4", ""),
CVAR("music_playlist_list5", "")
};
static cvar_t music_playlist_sampleposition[] =
{
CVAR("music_playlist_sampleposition0", "-1"),
CVAR("music_playlist_sampleposition1", "-1"),
CVAR("music_playlist_sampleposition2", "-1"),
CVAR("music_playlist_sampleposition3", "-1"),
CVAR("music_playlist_sampleposition4", "-1"),
CVAR("music_playlist_sampleposition5", "-1")
};
#define CVAR_ABUSE_LIMIT countof(music_playlist_list)
qboolean Media_Changed (unsigned int mediatype)
{
//something changed, but it has a lower priority so we don't care
if (mediatype < media_playlistcurrent)
return false;
//make sure we're not playing any cd music.
if (cdplayingtrack || cdpausedtrack)
{
@ -55,17 +93,14 @@ void Media_Clear (void)
}
#if !defined(NOMEDIA)
Q_strncpyz(currenttrack.filename, "", sizeof(currenttrack.filename));
fakecdactive = false;
media_playing = false;
media_fadeout = true;
media_fadeouttime = realtime;
#endif
return true;
}
//fake cd tracks.
qboolean Media_BackgroundTrack(const char *track, const char *looptrack)
qboolean Media_NamedTrack(const char *track, const char *looptrack)
{
unsigned int tracknum;
#if !defined(NOMEDIA)
@ -148,13 +183,10 @@ qboolean Media_BackgroundTrack(const char *track, const char *looptrack)
if (found)
{
cdplaytracknum = 0;
Q_strncpyz(cdplaytrack, trackname, sizeof(cdplaytrack));
Q_strncpyz(cdloopingtrack, looptrack, sizeof(cdloopingtrack));
Media_Clear();
Q_strncpyz(currenttrack.filename, trackname, sizeof(currenttrack.filename));
fakecdactive = true;
media_playing = true;
cdplayingtrack = tracknum;
Media_Changed(MEDIA_GAMEMUSIC);
return true;
}
#endif
@ -177,10 +209,10 @@ qboolean Media_BackgroundTrack(const char *track, const char *looptrack)
if (cdplayingtrack == tracknum)
return true; //already playing, don't need to do anything
Media_Clear();
cdpausedtrack = 0;
cdplayingtrack = tracknum;
CDAudio_Play(tracknum);
cdplaytracknum = tracknum;
Q_strncpyz(cdplaytrack, "", sizeof(cdplaytrack));
Q_strncpyz(cdloopingtrack, "", sizeof(cdloopingtrack));
Media_Changed(MEDIA_GAMEMUSIC);
return true;
}
return false;
@ -190,9 +222,9 @@ qboolean Media_BackgroundTrack(const char *track, const char *looptrack)
void Media_NamedTrack_f(void)
{
if (Cmd_Argc() == 3)
Media_BackgroundTrack(Cmd_Argv(1), Cmd_Argv(2));
Media_NamedTrack(Cmd_Argv(1), Cmd_Argv(2));
else
Media_BackgroundTrack(Cmd_Argv(1), Cmd_Argv(1));
Media_NamedTrack(Cmd_Argv(1), Cmd_Argv(1));
}
void Media_NumberedTrack(unsigned int initialtrack, unsigned int looptrack)
@ -200,7 +232,7 @@ void Media_NumberedTrack(unsigned int initialtrack, unsigned int looptrack)
char *init = initialtrack?va("%u", initialtrack):NULL;
char *loop = looptrack?va("%u", looptrack):NULL;
Media_BackgroundTrack(init, loop);
Media_NamedTrack(init, loop);
}
void Media_EndedTrack(void)
@ -209,7 +241,7 @@ void Media_EndedTrack(void)
cdpausedtrack = 0;
if (*cdloopingtrack)
Media_BackgroundTrack(cdloopingtrack, cdloopingtrack);
Media_NamedTrack(cdloopingtrack, cdloopingtrack);
}
@ -219,7 +251,7 @@ void Media_EndedTrack(void)
#include "winquake.h"
#if defined(_WIN32) && !defined(WINRT)
#define WINAMP
//#define WINAMP
#endif
#if defined(_WIN32) && !defined(WINRT)
#define WINAVI
@ -364,7 +396,8 @@ qboolean Media_EvaluateNextTrack(void)
{
if (!trnum)
{
memcpy(&currenttrack, track->filename, sizeof(mediatrack_t));
Q_strncpyz(media_currenttrack, track->filename, sizeof(media_currenttrack));
Q_strncpyz(media_friendlyname, track->nicename, sizeof(media_friendlyname));
lasttrackplayed = nexttrack;
break;
}
@ -385,10 +418,8 @@ qboolean Media_EvaluateNextTrack(void)
nexttrack = 0;
else
{
*currenttrack.filename='\0';
*currenttrack.nicename='\0';
nexttrack = -1;
media_playing = false;
*media_currenttrack='\0';
*media_friendlyname='\0';
return false;
}
}
@ -398,7 +429,8 @@ qboolean Media_EvaluateNextTrack(void)
{
if (!trnum)
{
memcpy(&currenttrack, track->filename, sizeof(mediatrack_t));
Q_strncpyz(media_currenttrack, track->filename, sizeof(media_currenttrack));
Q_strncpyz(media_friendlyname, track->nicename, sizeof(media_friendlyname));
lasttrackplayed = nexttrack;
break;
}
@ -443,16 +475,16 @@ void CD_f (void)
if (Q_strcasecmp(command, "play") == 0)
{
Media_BackgroundTrack(Cmd_Argv(2), "-");
Media_NamedTrack(Cmd_Argv(2), "-");
return;
}
if (Q_strcasecmp(command, "loop") == 0)
{
if (Cmd_Argc() < 4)
Media_BackgroundTrack(Cmd_Argv(2), NULL);
Media_NamedTrack(Cmd_Argv(2), NULL);
else
Media_BackgroundTrack(Cmd_Argv(2), Cmd_Argv(3));
Media_NamedTrack(Cmd_Argv(2), Cmd_Argv(3));
return;
}
@ -473,7 +505,9 @@ void CD_f (void)
if (Q_strcasecmp(command, "stop") == 0)
{
Media_Clear();
*cdplaytrack = *cdloopingtrack = 0;
cdplaytracknum = 0;
Media_Changed(MEDIA_GAMEMUSIC);
return;
}
@ -500,6 +534,10 @@ void CD_f (void)
if (cdplayingtrack || cdpausedtrack)
CDAudio_Stop();
cdenabled = false;
*cdplaytrack = *cdloopingtrack = 0;
cdplaytracknum = 0;
Media_Changed(MEDIA_GAMEMUSIC);
return;
}
@ -565,8 +603,7 @@ void CD_f (void)
//actually, this func just flushes and states that it should be playing. the ambientsound func actually changes the track.
void Media_Next_f (void)
{
Media_Clear();
media_playing=true;
Media_Changed(MEDIA_PLAYLIST);
#ifdef WINAMP
if (media_hijackwinamp.value)
@ -599,6 +636,9 @@ void Media_AddTrack(const char *fname)
newtrack->next = tracks;
tracks = newtrack;
numtracks++;
if (numtracks == 1)
Media_Changed(MEDIA_PLAYLIST);
}
void Media_RemoveTrack(const char *fname)
{
@ -611,8 +651,11 @@ void Media_RemoveTrack(const char *fname)
if (!strcmp(newtrack->filename, fname))
{
*link = newtrack->next;
Z_Free(newtrack);
numtracks--;
if (!strcmp(media_currenttrack, newtrack->filename))
Media_Changed(MEDIA_PLAYLIST);
Z_Free(newtrack);
return;
}
}
@ -661,7 +704,7 @@ void M_Media_Draw (menu_t *menu)
if (!bgmvolume.value)
M_Print (12, 32, "Not playing - no volume");
else if (!*currenttrack.nicename)
else if (!*media_currenttrack)
{
if (!tracks)
M_Print (12, 32, "Not playing - no track to play");
@ -678,7 +721,7 @@ void M_Media_Draw (menu_t *menu)
else
{
M_Print (12, 32, "Currently playing:");
M_Print (12, 40, currenttrack.nicename);
M_Print (12, 40, *media_friendlyname?media_friendlyname:media_currenttrack);
}
y=52;
@ -858,8 +901,10 @@ qboolean M_Media_Key (int key, menu_t *menu)
prevtrack->next = tr->next;
else
tracks = tr->next;
Z_Free(tr);
numtracks--;
if (!strcmp(media_currenttrack, tr->filename))
Media_Changed(MEDIA_PLAYLIST);
Z_Free(tr);
break;
}
@ -891,6 +936,7 @@ qboolean M_Media_Key (int key, menu_t *menu)
numtracks=0;
Con_SafePrintf("numtracks should be 0\n");
}
Media_Changed(MEDIA_PLAYLIST);
}
break;
case MEDIA_ADDTRACK:
@ -912,7 +958,6 @@ qboolean M_Media_Key (int key, menu_t *menu)
default:
if (selectedoption>=0)
{
media_playing = true;
nexttrack = selectedoption;
Media_Next_f();
return true;
@ -1093,7 +1138,7 @@ void Media_LoadTrackNames (char *listname)
#endif
//mixer is locked, its safe to do stuff, but try not to block
float Media_CrossFade(int musicchanel, float vol)
float Media_CrossFade(int musicchanel, float vol, float time)
{
if (media_fadeout)
{
@ -1101,44 +1146,85 @@ float Media_CrossFade(int musicchanel, float vol)
float frac = (fadetime + media_fadeouttime - realtime)/fadetime;
vol *= frac;
}
else if (music_playlist_index.modified)
{
if (Media_Changed(MEDIA_CVARLIST))
{
if (music_playlist_last >= 0 && music_playlist_sampleposition[music_playlist_last].value != -1)
{
Cvar_SetValue(&music_playlist_sampleposition[music_playlist_last], time);
}
vol = -1; //kill it NOW
}
}
return vol;
}
//mixer is locked, its safe to do stuff, but try not to block
char *Media_NextTrack(int musicchannelnum)
char *Media_NextTrack(int musicchannelnum, float *starttime)
{
if (bgmvolume.value <= 0 || !media_playing)
if (bgmvolume.value <= 0)
return NULL;
if (media_fadeout)
{
if (S_Music_Playing(musicchannelnum))
return NULL; //can't pick a new track until they've all stopped.
//okay, it has actually stopped everywhere.
}
media_fadeout = false; //it has actually ended now
if (!fakecdactive)
Media_EndedTrack();
media_fadeout = false;
#ifndef NOMEDIAMENU
if (!loadedtracknames)
Media_LoadTrackNames("sound/media.m3u");
#endif
if (!tracks && !fakecdactive)
music_playlist_index.modified = false;
music_playlist_last = -1;
media_playlistcurrent = 0;
Q_strncpyz(media_currenttrack, "", sizeof(media_currenttrack));
Q_strncpyz(media_friendlyname, "", sizeof(media_friendlyname));
if (!media_playlistcurrent && (media_playlisttypes & MEDIA_PLAYLIST))
{
*currenttrack.filename='\0';
*currenttrack.nicename='\0';
lasttrackplayed=-1;
media_playing = false;
return NULL;
#ifndef NOMEDIAMENU
if (!loadedtracknames)
Media_LoadTrackNames("sound/media.m3u");
#endif
if (Media_EvaluateNextTrack())
{
media_playlistcurrent = MEDIA_PLAYLIST;
return media_currenttrack;
}
}
if (!media_playlistcurrent && (media_playlisttypes & MEDIA_CVARLIST))
{
if (music_playlist_index.ival >= 0 && music_playlist_index.ival < countof(music_playlist_list))
{
Q_snprintfz(media_currenttrack, sizeof(media_currenttrack), "sound/cdtracks/%s", music_playlist_list[music_playlist_index.ival].string);
Q_strncpyz(media_friendlyname, "", sizeof(media_friendlyname));
media_playlistcurrent = MEDIA_CVARLIST;
music_playlist_last = music_playlist_index.ival;
*starttime = music_playlist_sampleposition[music_playlist_last].value;
if (*starttime == -1)
*starttime = 0;
}
}
if (!media_playlistcurrent && (media_playlisttypes & MEDIA_GAMEMUSIC))
{
if (cdplaytracknum)
{
if (cdplayingtrack != cdplaytracknum && cdpausedtrack != cdplaytracknum)
{
CDAudio_Play(cdplaytracknum);
cdplayingtrack = cdplaytracknum;
}
media_playlistcurrent = MEDIA_GAMEMUSIC;
}
else if (*cdplaytrack)
{
Q_strncpyz(media_currenttrack, cdplaytrack, sizeof(media_currenttrack));
Q_strncpyz(media_friendlyname, "", sizeof(media_friendlyname));
media_playlistcurrent = MEDIA_GAMEMUSIC;
}
}
fakecdactive = false;
// if (cursndcard == sndcardinfo) //figure out the next track (primary sound card, we could actually get different tracks on different cards (and unfortunatly do))
// {
Media_EvaluateNextTrack();
// }
return currenttrack.filename;
return media_currenttrack;
}
@ -4003,6 +4089,7 @@ qboolean S_LoadMP3Sound (sfx_t *s, qbyte *data, int datalen, int sndspeed);
void Media_Init(void)
{
int i;
#if defined(_WIN32) && !defined(WINRT)
Cmd_AddCommand("tts", TTS_Say_f);
Cmd_AddCommand("stt", STT_Init_f);
@ -4020,8 +4107,17 @@ void Media_Init(void)
Cmd_AddCommand("music_fforward", Media_FForward_f);
Cmd_AddCommand("music_rewind", Media_Rewind_f);
Cmd_AddCommand("music_next", Media_Next_f);
Cmd_AddCommand("media_next", Media_Next_f);
Cmd_AddCommand("music", Media_NamedTrack_f);
Cvar_Register(&music_playlist_index, "compat");
for (i = 0; i < countof(music_playlist_list); i++)
{
Cvar_Register(&music_playlist_list[i], "compat");
Cvar_Register(&music_playlist_sampleposition[i], "compat");
}
music_playlist_last = -1;
Cmd_AddCommand("cd", CD_f);
cdenabled = false;
if (COM_CheckParm("-nocdaudio"))
@ -4029,6 +4125,8 @@ void Media_Init(void)
if (COM_CheckParm("-cdaudio"))
cdenabled = true;
media_playlisttypes = MEDIA_PLAYLIST | MEDIA_GAMEMUSIC | MEDIA_CVARLIST;
#if defined(GLQUAKE)
Cmd_AddCommand("capture", Media_RecordFilm_f);
Cmd_AddCommand("capturedemo", Media_RecordDemo_f);
@ -4056,7 +4154,7 @@ void Media_Init(void)
Cvar_Register(&media_shuffle, "Media player things");
Cvar_Register(&media_repeat, "Media player things");
Cmd_AddCommand ("media_add", M_Media_Add_f);
Cmd_AddCommand ("media_rmeove", M_Media_Remove_f);
Cmd_AddCommand ("media_remove", M_Media_Remove_f);
Cmd_AddCommand ("menu_media", M_Menu_Media_f);
}
@ -4099,7 +4197,7 @@ static void S_MP3_Purge(sfx_t *sfx)
}
/*must be thread safe*/
sfxcache_t *S_MP3_Locate(sfx_t *sfx, sfxcache_t *buf, int start, int length)
sfxcache_t *S_MP3_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start, int length)
{
int newlen;
if (buf)

View File

@ -349,7 +349,7 @@ void M_Audio_StartSound (struct menu_s *menu)
if (lasttime+0.5 < Sys_DoubleTime())
{
S_GetListenerInfo(mat[0], mat[1], mat[2], mat[3]);
S_GetListenerInfo(0, mat[0], mat[1], mat[2], mat[3]);
lasttime = Sys_DoubleTime();
org[0] = mat[0][0] + 2*(mat[1][0]*(info->testsoundsource->common.posx-320/2) + mat[1][0]*(info->testsoundsource->common.posy-200/2));

View File

@ -13,6 +13,9 @@ void M_Script_Option (menu_t *menu, char *optionvalue)
menuoption_t *mo;
char buf[8192];
Cbuf_AddText("wait\n", RESTRICT_LOCAL);
//update the option
Cbuf_AddText(va("set option %s\n", COM_QuotedString(optionvalue, buf, sizeof(buf), false)), RESTRICT_LOCAL);

View File

@ -105,19 +105,32 @@ void M_DrawTextBox (int x, int y, int width, int lines)
M_DrawScalePic (cx, cy+8, 8, 8, p);
}
int M_FindKeysForBind (const char *command, int *keylist, int *keymods, int total)
int M_FindKeysForBind (int bindmap, const char *command, int *keylist, int *keymods, int keycount)
{
int count;
int j, m;
int l, p;
char *b;
int firstmod, lastmod;
l = strlen(command);
count = 0;
if (bindmap > 0 && bindmap <= KEY_MODIFIER_ALTBINDMAP)
{
//bindmaps don't support modifiers
firstmod = (bindmap-1)|KEY_MODIFIER_ALTBINDMAP;
lastmod = firstmod+1;
}
else
{
firstmod = 0;
lastmod = KEY_MODIFIER_ALTBINDMAP;
}
for (j=0 ; j<256 ; j++)
{
for (m = 0; m < KEY_MODIFIERSTATES; m++)
for (m = firstmod; m < lastmod; m++)
{
b = keybindings[j][m];
if (!b)
@ -125,11 +138,11 @@ int M_FindKeysForBind (const char *command, int *keylist, int *keymods, int tota
if (!strncmp (b, command, l) && (!b[l] || b[l] == ' ' || b[l] == ';'))
{
//if ctrl_a and ctrl_shift_a do the same thing, don't report ctrl_shift_a because its redundant.
for (p = 0; p < m; p++)
for (p = firstmod; p < m; p++)
{
if (p&~m) //ignore shift_a if we're checking ctrl_a
continue;
if (!strcmp(keybindings[j][p], b))
if (keybindings[j][p] && !strcmp(keybindings[j][p], b))
break; //break+continue
}
if (p != m)
@ -137,14 +150,14 @@ int M_FindKeysForBind (const char *command, int *keylist, int *keymods, int tota
keylist[count] = j;
if (keymods)
keymods[count] = j;
keymods[count] = m;
count++;
if (count == total)
if (count == keycount)
return count;
}
}
}
for (j = count; j < total; j++)
for (j = count; j < keycount; j++)
{
keylist[j] = -1;
if (keymods)
@ -152,7 +165,7 @@ int M_FindKeysForBind (const char *command, int *keylist, int *keymods, int tota
}
return count;
}
void M_FindKeysForCommand (int pnum, const char *command, int *twokeys)
int M_FindKeysForCommand (int bindmap, int pnum, const char *command, int *keylist, int *keymods, int keycount)
{
char prefix[5];
@ -180,7 +193,7 @@ void M_FindKeysForCommand (int pnum, const char *command, int *twokeys)
prefix[3] = 0;
}
}
M_FindKeysForBind(va("%s%s", prefix, command), twokeys, NULL, 2);
return M_FindKeysForBind(bindmap, va("%s%s", prefix, command), keylist, keymods, keycount);
}
#ifndef NOBUILTINMENUS
@ -582,16 +595,20 @@ void M_UnbindCommand (const char *command)
int j;
int l;
char *b;
int m;
l = strlen(command);
for (j=0 ; j<256 ; j++)
{
b = keybindings[j][0];
if (!b)
continue;
if (!strncmp (b, command, l) )
Key_SetBinding (j, ~0, "", RESTRICT_LOCAL);
{ //FIXME: not sure what to do about bindmaps here. oh well.
for (m = 0; m < KEY_MODIFIERSTATES; m++)
{
b = keybindings[j][m];
if (!b)
continue;
if (!strncmp (b, command, l) )
Key_SetBinding (j, m, "", RESTRICT_LOCAL);
}
}
}
@ -1406,6 +1423,8 @@ void M_Keydown (int key, int unicode)
case m_complex:
if (key == K_MOUSE1) //mouse clicks are deferred until the release event. this is for touch screens and aiming.
menu_mousedown = true;
else if (key == K_LSHIFT || key == K_RSHIFT || key == K_LALT || key == K_RALT || key == K_LCTRL || key == K_RCTRL)
;
else
M_Complex_Key (key, unicode);
return;
@ -1428,6 +1447,8 @@ void M_Keyup (int key, int unicode)
case m_complex:
if (key == K_MOUSE1 && menu_mousedown)
M_Complex_Key (key, unicode);
else if (key == K_LSHIFT || key == K_RSHIFT || key == K_LALT || key == K_RALT || key == K_LCTRL || key == K_RCTRL)
M_Complex_Key (key, unicode);
menu_mousedown = false;
return;
#endif

View File

@ -456,8 +456,8 @@ void M_Keydown (int key, int unicode);
void M_Keyup (int key, int unicode);
void M_Draw (int uimenu);
#endif
void M_FindKeysForCommand (int pnum, const char *command, int *twokeys);
int M_FindKeysForBind (const char *command, int *keylist, int *keymods, int total);
int M_FindKeysForCommand (int bindmap, int pnum, const char *command, int *keylist, int *keymods, int keycount);
int M_FindKeysForBind (int bindmap, const char *command, int *keylist, int *keymods, int keycount);
#ifdef MENU_DAT
void MP_CvarChanged(cvar_t *var);

View File

@ -229,6 +229,7 @@ typedef struct image_s
unsigned int flags;
struct image_s *next;
struct image_s *prev;
struct image_s *aliasof;
#if defined(D3DQUAKE) || defined(SWQUAKE)
void *ptr; //texture
void *ptr2; //view

View File

@ -34,13 +34,6 @@ The engine has a few builtins.
#endif
#include "shader.h"
#ifdef D3DQUAKE
//d3d is awkward
//we can't include two versions of header files
extern void *d3dexplosiontexture;
extern void *d3dballtexture;
#endif
#include "renderque.h"
#include "r_partset.h"
@ -152,7 +145,7 @@ typedef struct skytriblock_s
//this is the required render state for each particle
//dynamic per-particle stuff isn't important. only static state.
typedef struct {
enum {PT_NORMAL, PT_SPARK, PT_SPARKFAN, PT_TEXTUREDSPARK, PT_BEAM, PT_CDECAL, PT_UDECAL} type;
enum {PT_NORMAL, PT_SPARK, PT_SPARKFAN, PT_TEXTUREDSPARK, PT_BEAM, PT_CDECAL, PT_UDECAL, PT_INVISIBLE} type;
blendmode_t blendmode;
shader_t *shader;
@ -779,7 +772,13 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
ptype->s2 = 1;
ptype->t2 = 1;
ptype->randsmax = 1;
if (ptype->looks.type == PT_BEAM)
if (ptype->looks.type == PT_SPARK)
{
extern texid_t r_whiteimage;
ptype->looks.shader = R_RegisterShader(va("line%s", namepostfix), SUF_NONE, defaultshader);
TEXASSIGNF(tn.base, r_whiteimage);
}
else if (ptype->looks.type == PT_BEAM)
{
/*untextured beams get a single continuous blob*/
ptype->looks.shader = R_RegisterShader(va("beam%s", namepostfix), SUF_NONE, defaultshader);
@ -904,7 +903,7 @@ void Cmd_if_f(void);
//Uses FTE's multiline console stuff.
//This is the function that loads the effect descriptions (via console).
static void P_ParticleEffect_f(void)
void P_ParticleEffect_f(void)
{
char *var, *value;
char *buf;
@ -940,7 +939,9 @@ static void P_ParticleEffect_f(void)
}
var = Cmd_Argv(1);
if (*var == '+')
if (!pe_script_enabled)
ptype = NULL;
else if (*var == '+')
ptype = P_GetParticleType(config, var+1);
else
ptype = P_GetParticleType(config, var);
@ -1827,6 +1828,17 @@ static void P_ParticleEffect_f(void)
}
}
if (ptype->looks.type == PT_SPARK && r_part_sparks.ival<0)
ptype->looks.type = PT_INVISIBLE;
if (ptype->looks.type == PT_TEXTUREDSPARK && !r_part_sparks_textured.ival)
ptype->looks.type = PT_SPARK;
if (ptype->looks.type == PT_SPARKFAN && !r_part_sparks_trifan.ival)
ptype->looks.type = PT_SPARK;
if (ptype->looks.type == PT_SPARK && !r_part_sparks.ival)
ptype->looks.type = PT_INVISIBLE;
if (ptype->looks.type == PT_BEAM && r_part_beams.ival <= 0)
ptype->looks.type = PT_INVISIBLE;
if (ptype->looks.type == PT_BEAM && !setbeamlen)
ptype->rotationstartmin = 1/128.0;
@ -2219,6 +2231,7 @@ static void P_BeamInfo_f (void)
static void P_PartInfo_f (void)
{
particle_t *p;
clippeddecal_t *d;
part_type_t *ptype;
int t = 0, r = 0, e = 0;
@ -2237,6 +2250,8 @@ static void P_PartInfo_f (void)
j = 0;
for (p = part_type[i].particles; p; p = p->next)
j++;
for (d = part_type[i].clippeddecals; d; d = d->next)
j++;
if (j)
{
@ -2731,7 +2746,6 @@ static qboolean PScript_InitParticles (void)
Cmd_AddCommand("pointfile", P_ReadPointFile_f); //load the leak info produced from qbsp into the particle system to show a line. :)
Cmd_AddCommand("r_part", P_ParticleEffect_f);
pe_script_enabled = true;
Cmd_AddCommand("r_exportbuiltinparticles", P_ExportBuiltinSet_f);
@ -3670,7 +3684,7 @@ static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t axis[3]
if (w <= tw)
{
if (*ptype->sounds[i].name && ptype->sounds[i].vol > 0)
S_StartSound(0, 0, S_PrecacheSound(ptype->sounds[i].name), org, ptype->sounds[i].vol, ptype->sounds[i].atten, ptype->sounds[i].delay, ptype->sounds[i].pitch);
S_StartSound(0, 0, S_PrecacheSound(ptype->sounds[i].name), org, ptype->sounds[i].vol, ptype->sounds[i].atten, -ptype->sounds[i].delay, ptype->sounds[i].pitch);
break;
}
}
@ -3903,6 +3917,9 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
Matrix4x4_CM_Transform3(Matrix4x4_CM_NewRotation(frandom()*360, dir[0], dir[1], dir[2]), ctx.tangent1, ctx.tangent2);
CrossProduct(dir, ctx.tangent2, ctx.tangent1);
VectorNormalize(ctx.tangent1);
VectorNormalize(ctx.tangent2);
ctx.ptype = ptype;
ctx.scale1 = ptype->s2 - ptype->s1;
ctx.bias1 = ptype->s1 + ctx.scale1/2;
@ -5227,45 +5244,38 @@ static void GL_DrawTrifanParticle(int count, particle_t **plist, plooks_t *type)
}
}
static void R_AddLineSparkParticle(int count, particle_t **plist, plooks_t *type)
//static void R_AddLineSparkParticle(int count, particle_t **plist, plooks_t *type)
static void R_AddLineSparkParticle(scenetris_t *t, particle_t *p, plooks_t *type)
{
/*
particle_t *p;
while (count--)
if (cl_numstrisvert+2 > cl_maxstrisvert)
{
p = *plist++;
if (cl_numstrisvert+2 > cl_maxstrisvert)
{
cl_maxstrisvert+=64*2;
cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert);
cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(*cl_strisvertt)*cl_maxstrisvert);
cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert);
}
Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]);
VectorCopy(p->rgba, cl_strisvertc[cl_numstrisvert+1]);
cl_strisvertc[cl_numstrisvert+1][3] = 0;
Vector2Set(cl_strisvertt[cl_numstrisvert+0], p->s1, p->t1);
Vector2Set(cl_strisvertt[cl_numstrisvert+1], p->s2, p->t2);
VectorCopy(p->org, cl_strisvertv[cl_numstrisvert+0]);
VectorMA(p->org, -1/10, p->vel, cl_strisvertv[cl_numstrisvert+1]);
if (cl_numstrisidx+2 > cl_maxstrisidx)
{
cl_maxstrisidx += 64*2;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 0;
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 1;
cl_numstrisvert += 2;
t->numvert += 2;
t->numidx += 2;
cl_maxstrisvert+=64*2;
cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert);
cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(*cl_strisvertt)*cl_maxstrisvert);
cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert);
}
*/
Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]);
VectorCopy(p->rgba, cl_strisvertc[cl_numstrisvert+1]);
cl_strisvertc[cl_numstrisvert+1][3] = 0;
Vector2Set(cl_strisvertt[cl_numstrisvert+0], p->s1, p->t1);
Vector2Set(cl_strisvertt[cl_numstrisvert+1], p->s2, p->t2);
VectorCopy(p->org, cl_strisvertv[cl_numstrisvert+0]);
VectorMA(p->org, -1.0/10, p->vel, cl_strisvertv[cl_numstrisvert+1]);
if (cl_numstrisidx+2 > cl_maxstrisidx)
{
cl_maxstrisidx += 64*2;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 0;
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 1;
cl_numstrisvert += 2;
t->numvert += 2;
t->numidx += 2;
}
static void R_AddTSparkParticle(scenetris_t *t, particle_t *p, plooks_t *type)
@ -5763,7 +5773,7 @@ static void R_AddTexturedParticle(scenetris_t *t, particle_t *p, plooks_t *type)
static void PScript_DrawParticleTypes (void)
{
void (*sparklineparticles)(int count, particle_t **plist, plooks_t *type)=R_AddLineSparkParticle;
// void (*sparklineparticles)(int count, particle_t **plist, plooks_t *type)=R_AddLineSparkParticle;
void (*sparkfanparticles)(int count, particle_t **plist, plooks_t *type)=GL_DrawTrifanParticle;
void (*sparktexturedparticles)(int count, particle_t **plist, plooks_t *type)=GL_DrawTexturedSparkParticle;
@ -5789,6 +5799,7 @@ static void PScript_DrawParticleTypes (void)
int traces=r_particle_tracelimit.ival;
int rampind;
static float oldtime;
int batchflags;
RSpeedMark();
if (r_plooksdirty)
@ -5827,25 +5838,6 @@ static void PScript_DrawParticleTypes (void)
kill_list = kill_first = NULL;
if (r_part_sparks_textured.ival < 0)
sparktexturedparticles = NULL;
else if (!r_part_sparks_textured.ival)
sparktexturedparticles = sparklineparticles;
if (r_part_sparks_trifan.ival < 0)
sparkfanparticles = NULL;
else if (!r_part_sparks_trifan.ival)
sparkfanparticles = sparklineparticles;
if (r_part_sparks.ival < 0)
sparklineparticles = NULL;
else if (!r_part_sparks.ival)
{
sparktexturedparticles = NULL;
sparkfanparticles = NULL;
sparklineparticles = NULL;
}
for (type = part_run_list, lastvalidtype = NULL; type != NULL; type = type->nexttorun)
{
if (type->clippeddecals)
@ -5940,16 +5932,14 @@ static void PScript_DrawParticleTypes (void)
bdraw = NULL;
pdraw = NULL;
tdraw = NULL;
batchflags = 0;
// set drawing methods by type and cvars and hope branch
// prediction takes care of the rest
switch(type->looks.type)
{
case PT_BEAM:
if (r_part_beams.ival <= 0)
bdraw = NULL;
else
bdraw = GL_DrawParticleBeam;
bdraw = GL_DrawParticleBeam;
break;
case PT_CDECAL:
break;
@ -5961,7 +5951,8 @@ static void PScript_DrawParticleTypes (void)
tdraw = R_AddTexturedParticle;
break;
case PT_SPARK:
pdraw = sparklineparticles;
tdraw = R_AddLineSparkParticle;
batchflags = BEF_LINES;
break;
case PT_SPARKFAN:
pdraw = sparkfanparticles;
@ -5974,7 +5965,7 @@ static void PScript_DrawParticleTypes (void)
if (!tdraw || type->looks.shader->sort == SHADER_SORT_BLEND)
scenetri = NULL;
else if (cl_numstris && cl_stris[cl_numstris-1].shader == type->looks.shader && cl_stris[cl_numstris-1].flags == 0)
else if (cl_numstris && cl_stris[cl_numstris-1].shader == type->looks.shader && cl_stris[cl_numstris-1].flags == batchflags)
scenetri = &cl_stris[cl_numstris-1];
else
{
@ -5987,7 +5978,7 @@ static void PScript_DrawParticleTypes (void)
scenetri->shader = type->looks.shader;
scenetri->firstidx = cl_numstrisidx;
scenetri->firstvert = cl_numstrisvert;
scenetri->flags = 0;
scenetri->flags = batchflags;
scenetri->numvert = 0;
scenetri->numidx = 0;
}

View File

@ -285,11 +285,11 @@ int MP_TranslateQCtoFTECodes(int code)
void QCBUILTIN PF_cl_findkeysforcommand (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *cmdname = PR_GetStringOfs(prinst, OFS_PARM0);
//float bindmap = G_FLOAT(OFS_PARM1);
int bindmap = G_FLOAT(OFS_PARM1);
int keynums[2];
char keyname[512];
M_FindKeysForCommand(0, cmdname, keynums);
M_FindKeysForCommand(bindmap, 0, cmdname, keynums, NULL, countof(keynums));
keyname[0] = '\0';
@ -302,18 +302,19 @@ void QCBUILTIN PF_cl_findkeysforcommand (pubprogfuncs_t *prinst, struct globalva
void QCBUILTIN PF_cl_findkeysforcommandex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *cmdname = PR_GetStringOfs(prinst, OFS_PARM0);
int bindmap = G_FLOAT(OFS_PARM1);
int keynums[256];
int keymods[countof(keynums)];
char keyname[512];
int i, count;
count = M_FindKeysForBind(cmdname, keynums, keymods, countof(keynums));
count = M_FindKeysForBind(bindmap, cmdname, keynums, keymods, countof(keynums));
keyname[0] = '\0';
for (i = 0; i < count; i++)
{
Q_strncatz (keyname, va("%s%s%s%s ", (keymods[i]&KEY_MODIFIER_CTRL)?"CTRL_":"", (keymods[i]&KEY_MODIFIER_ALT)?"ALT_":"", (keymods[i]&KEY_MODIFIER_SHIFT)?"SHIFT_":"", Key_KeynumToString(keynums[i])), sizeof(keyname));
Q_strncatz (keyname, Key_KeynumToString(keynums[i], keymods[i]), sizeof(keyname));
}
RETURN_TSTRING(keyname);
@ -321,7 +322,9 @@ void QCBUILTIN PF_cl_findkeysforcommandex (pubprogfuncs_t *prinst, struct global
void QCBUILTIN PF_cl_getkeybind (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *binding = Key_GetBinding(MP_TranslateQCtoFTECodes(G_FLOAT(OFS_PARM0)));
int keymap = (prinst->callargc > 1)?G_FLOAT(OFS_PARM1):0;
int modifier = (prinst->callargc > 2)?G_FLOAT(OFS_PARM2):0;
char *binding = Key_GetBinding(MP_TranslateQCtoFTECodes(G_FLOAT(OFS_PARM0)), keymap, modifier);
RETURN_TSTRING(binding);
}
@ -349,7 +352,7 @@ void QCBUILTIN PF_cl_keynumtostring (pubprogfuncs_t *prinst, struct globalvars_s
code = MP_TranslateQCtoFTECodes (code);
RETURN_TSTRING(Key_KeynumToString(code));
RETURN_TSTRING(Key_KeynumToString(code, 0));
}
@ -700,17 +703,21 @@ void QCBUILTIN PF_shaderforname (pubprogfuncs_t *prinst, struct globalvars_s *pr
void QCBUILTIN PF_cl_GetBindMap (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_VECTOR(OFS_RETURN)[0] = 1;
G_VECTOR(OFS_RETURN)[1] = 0;
int bm[2];
Key_GetBindMap(bm);
G_VECTOR(OFS_RETURN)[0] = bm[0];
G_VECTOR(OFS_RETURN)[1] = bm[1];
G_VECTOR(OFS_RETURN)[2] = 0;
}
void QCBUILTIN PF_cl_SetBindMap (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
// int primary = G_FLOAT(OFS_PARM0+0);
// int secondary = G_FLOAT(OFS_PARM0+1);
// if (IN_SetBindMap(primary, secondary))
// G_FLOAT(OFS_RETURN) = 1;
G_FLOAT(OFS_RETURN) = 0;
int bm[2] =
{
G_FLOAT(OFS_PARM0+0),
G_FLOAT(OFS_PARM0+1)
};
Key_SetBindMap(bm);
G_FLOAT(OFS_RETURN) = 1;
}
//evil builtins to pretend to be a server.

View File

@ -67,6 +67,7 @@ world_t csqc_world;
int csqc_playerseat; //can be negative.
static playerview_t *csqc_playerview;
qboolean csqc_dp_lastwas3d; //to emulate DP correctly, we need to track whether drawpic/drawfill or clearscene was called last. blame 515.
static qboolean csqc_isdarkplaces;
static qboolean csqc_singlecheats; /*single player or cheats active, allowing custom addons*/
static qboolean csqc_mayread; //csqc is allowed to ReadByte();
@ -276,7 +277,7 @@ static void CSQC_ChangeLocalPlayer(int seat)
}
}
static void CSQC_FindGlobals(void)
static void CSQC_FindGlobals(qboolean nofuncs)
{
static float csphysicsmode = 0;
static float dimension_default = 255;
@ -285,7 +286,7 @@ static void CSQC_FindGlobals(void)
#define globalvector(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
#define globalentity(name,qcname) csqcg.name = (int*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
#define globalstring(name,qcname) csqcg.name = (string_t*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
#define globalfunction(name,qcname) csqcg.name = PR_FindFunction(csqcprogs,qcname,PR_ANY);
#define globalfunction(name,qcname) csqcg.name = nofuncs?0:PR_FindFunction(csqcprogs,qcname,PR_ANY);
csqcglobals
@ -876,7 +877,7 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa
l->rebuildcache = true;
break;
case lfield_style:
l->style = G_FLOAT(OFS_PARM2);
l->style = G_FLOAT(OFS_PARM2)+1;
break;
case lfield_angles:
AngleVectors(G_VECTOR(OFS_PARM2), l->axis[0], l->axis[1], l->axis[2]);
@ -960,11 +961,11 @@ static void QCBUILTIN PF_R_DynamicLight_Get(pubprogfuncs_t *prinst, struct globa
G_FLOAT(OFS_RETURN) = l->flags;
break;
case lfield_style:
G_FLOAT(OFS_RETURN) = l->style;
G_FLOAT(OFS_RETURN) = l->style-1;
break;
case lfield_angles:
VectorAngles(l->axis[0], l->axis[2], v);
G_FLOAT(OFS_RETURN+0) = v[0]?v[0]:0;
G_FLOAT(OFS_RETURN+0) = anglemod(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;
@ -1172,12 +1173,31 @@ static shader_t *csqc_poly_shader;
static int csqc_poly_startvert;
static int csqc_poly_startidx;
static int csqc_poly_flags;
static int csqc_poly_2d;
// #306 void(string texturename) R_BeginPolygon (EXT_CSQC_???)
void QCBUILTIN PF_R_PolygonBegin(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqc_poly_flags = (prinst->callargc > 1)?G_FLOAT(OFS_PARM1):0;
if (csqc_poly_flags & 4)
if (prinst->callargc > 2)
csqc_poly_2d = G_FLOAT(OFS_PARM2);
else if (csqc_isdarkplaces)
{
csqc_poly_2d = !csqc_dp_lastwas3d;
csqc_deprecated("guessing 2d mode based upon random builtin calls");
}
else
csqc_poly_2d = csqc_poly_flags & 4;
if ((csqc_poly_flags & 3) == 1)
csqc_poly_flags = BEF_FORCEADDITIVE;
else
csqc_poly_flags = BEF_NOSHADOWS;
if (csqc_isdarkplaces)
csqc_poly_flags |= BEF_FORCETWOSIDED;
if (csqc_poly_2d)
csqc_poly_shader = R_RegisterPic(PR_GetStringOfs(prinst, OFS_PARM0));
else
csqc_poly_shader = R_RegisterSkin(PR_GetStringOfs(prinst, OFS_PARM0), NULL);
@ -1209,7 +1229,7 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
scenetris_t *t;
int i;
int nv;
int flags = BEF_NOSHADOWS;
int flags = csqc_poly_flags;
if (!csqc_poly_shader)
return;
@ -1271,7 +1291,7 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
}
}
if (csqc_poly_flags & 4)
if (csqc_poly_2d)
{
mesh_t mesh;
memset(&mesh, 0, sizeof(mesh));
@ -1287,7 +1307,7 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
cl_numstrisvert = csqc_poly_startvert;
cl_numstrisidx = csqc_poly_startidx;
BE_DrawMesh_Single(csqc_poly_shader, &mesh, NULL, 0);
BE_DrawMesh_Single(csqc_poly_shader, &mesh, NULL, csqc_poly_flags);
}
else
{
@ -1404,6 +1424,8 @@ static void QCBUILTIN PF_R_ClearScene (pubprogfuncs_t *prinst, struct globalvars
CSQC_ChangeLocalPlayer(G_FLOAT(OFS_PARM0));
csqc_rebuildmatricies = true;
csqc_dp_lastwas3d = true; //cleared by the next drawpic.
csqc_poly_shader = NULL;
CL_DecayLights ();
@ -1770,6 +1792,8 @@ void R2D_PolyBlend (void);
void R_DrawNameTags(void);
static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqc_poly_shader = NULL;
if (csqc_worldchanged)
{
csqc_worldchanged = false;
@ -1802,15 +1826,17 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars
if (r_refdef.drawsbar)
{
SCR_TileClear ();
#ifdef PLUGINS
Plug_SBar (r_refdef.playerview);
#else
if (Sbar_ShouldDraw())
{
SCR_TileClear (sb_lines);
Sbar_Draw (r_refdef.playerview);
Sbar_DrawScoreboard ();
}
else
SCR_TileClear (0);
#endif
SCR_ShowPics_Draw();
}
@ -1824,8 +1850,16 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars
static void QCBUILTIN PF_cs_getstati(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int stnum = G_FLOAT(OFS_PARM0);
if (stnum >= 128 && csqc_isdarkplaces)
if (stnum < 0 || stnum >= MAX_CL_STATS)
{
G_FLOAT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "invalid stat index");
}
else if (stnum >= 128 && csqc_isdarkplaces)
{ //dpp7 stats are fucked.
G_FLOAT(OFS_RETURN) = csqc_playerview->statsf[stnum];
csqc_deprecated("hacked stat type");
}
else
G_INT(OFS_RETURN) = csqc_playerview->stats[stnum];
}
@ -1834,7 +1868,12 @@ static void QCBUILTIN PF_cs_getstatbits(pubprogfuncs_t *prinst, struct globalvar
//if bits offsets are specified, reads explicitly the integer version of the stat, allowing high bits to be read for items2/serverflags. the float stat should have the same value, just with lower precision as a float can't hold a 32bit value. maybe we should just use doubles.
int stnum = G_FLOAT(OFS_PARM0);
if (prinst->callargc > 1)
if (stnum < 0 || stnum >= MAX_CL_STATS)
{
G_FLOAT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "invalid stat index");
}
else if (prinst->callargc > 1)
{
int val = csqc_playerview->stats[stnum];
int first, count;
@ -1846,7 +1885,11 @@ static void QCBUILTIN PF_cs_getstatbits(pubprogfuncs_t *prinst, struct globalvar
G_FLOAT(OFS_RETURN) = (((unsigned int)val)&(((1<<count)-1)<<first))>>first;
}
else if (csqc_isdarkplaces)
G_FLOAT(OFS_RETURN) = (int)csqc_playerview->statsf[stnum]; //stupid. mods like xonotic have a stupid hud if they're actually given any precision
{
G_FLOAT(OFS_RETURN) = (int)csqc_playerview->statsf[stnum]; //stupid. mods like xonotic end up with an ugly hud if they're actually given any precision
if (G_FLOAT(OFS_RETURN) != csqc_playerview->statsf[stnum])
csqc_deprecated("getstatf stat truncation"); //this is a common call. only get pissy if there's a reason to get pissy.
}
else
G_FLOAT(OFS_RETURN) = csqc_playerview->statsf[stnum];
}
@ -1854,20 +1897,32 @@ static void QCBUILTIN PF_cs_getstats(pubprogfuncs_t *prinst, struct globalvars_s
{
int stnum = G_FLOAT(OFS_PARM0);
RETURN_TSTRING(csqc_playerview->statsstr[stnum]);
if (stnum < 0 || stnum >= MAX_CL_STATS)
{
G_INT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "invalid stat index");
}
else if (cls.fteprotocolextensions & PEXT_CSQC)
RETURN_TSTRING(csqc_playerview->statsstr[stnum]);
else if (stnum >= MAX_CL_STATS-3)
{
G_INT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "invalid stat index");
}
else
{
char out[17];
/*
char out[17];
//the network protocol byteswaps
//the network protocol byteswaps
((unsigned int*)out)[0] = LittleLong(csqc_playerview->stats[stnum+0]);
((unsigned int*)out)[1] = LittleLong(csqc_playerview->stats[stnum+1]);
((unsigned int*)out)[2] = LittleLong(csqc_playerview->stats[stnum+2]);
((unsigned int*)out)[3] = LittleLong(csqc_playerview->stats[stnum+3]);
((unsigned int*)out)[4] = 0; //make sure it's null terminated
((unsigned int*)out)[0] = LittleLong(csqc_playerview->stats[stnum+0]);
((unsigned int*)out)[1] = LittleLong(csqc_playerview->stats[stnum+1]);
((unsigned int*)out)[2] = LittleLong(csqc_playerview->stats[stnum+2]);
((unsigned int*)out)[3] = LittleLong(csqc_playerview->stats[stnum+3]);
((unsigned int*)out)[4] = 0; //make sure it's null terminated
RETURN_TSTRING(out);*/
RETURN_TSTRING(out);
}
}
static void QCBUILTIN PF_cs_SetOrigin(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -1877,7 +1932,7 @@ static void QCBUILTIN PF_cs_SetOrigin(pubprogfuncs_t *prinst, struct globalvars_
float *org = G_VECTOR(OFS_PARM1);
if (ent->readonly)
{
Con_Printf("setorigin on entity %i\n", ent->entnum);
PR_RunWarning(prinst, "setorigin on entity %i\n", ent->entnum);
return;
}
VectorCopy(org, ent->v->origin);
@ -2956,6 +3011,10 @@ static void QCBUILTIN PF_cs_serverkey (pubprogfuncs_t *prinst, struct globalvars
if (!ret)
ret = "";
}
else if (!strcmp(keyname, "maxplayers"))
{
ret = va("%i", cl.allocated_client_slots);
}
else if (!strcmp(keyname, "dlstate"))
{
if (!cl.downloadlist && !cls.download)
@ -3192,12 +3251,34 @@ static void QCBUILTIN PF_checkextension (pubprogfuncs_t *prinst, struct globalva
G_FLOAT(OFS_RETURN) = false;
}
void QCBUILTIN PF_soundupdate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
wedict_t *entity = G_WEDICT(prinst, OFS_PARM0);
int channel = G_FLOAT(OFS_PARM1);
const char *sample = PR_GetStringOfs(prinst, OFS_PARM2);
float volume = G_FLOAT(OFS_PARM3);
float attenuation = G_FLOAT(OFS_PARM4);
float pitchpct = (prinst->callargc >= 6)?G_FLOAT(OFS_PARM5):0;
// unsigned int flags = (prinst->callargc>=7)?G_FLOAT(OFS_PARM6):0;
float startoffset = (prinst->callargc>=8)?G_FLOAT(OFS_PARM7):0;
sfx_t *sfx = S_PrecacheSound(sample);
G_FLOAT(OFS_RETURN) = S_UpdateSound(-entity->entnum, channel, sfx, entity->v->origin, volume, attenuation, startoffset, pitchpct);
}
void QCBUILTIN PF_stopsound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
wedict_t *entity = G_WEDICT(prinst, OFS_PARM0);
int channel = G_FLOAT(OFS_PARM1);
S_StopSound(-entity->entnum, channel);
}
void QCBUILTIN PF_getsoundtime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
wedict_t *entity = G_WEDICT(prinst, OFS_PARM0);
int channel = G_FLOAT(OFS_PARM1);
G_FLOAT(OFS_RETURN) = S_GetSoundTime(entity->entnum, channel);
G_FLOAT(OFS_RETURN) = S_GetSoundTime(-entity->entnum, channel);
}
static void QCBUILTIN PF_cs_sound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -3207,6 +3288,8 @@ static void QCBUILTIN PF_cs_sound(pubprogfuncs_t *prinst, struct globalvars_s *p
float volume;
float attenuation;
float pitchpct;
// unsigned int flags;
float startoffset;
sfx_t *sfx;
@ -3215,14 +3298,13 @@ static void QCBUILTIN PF_cs_sound(pubprogfuncs_t *prinst, struct globalvars_s *p
sample = PR_GetStringOfs(prinst, OFS_PARM2);
volume = G_FLOAT(OFS_PARM3);
attenuation = G_FLOAT(OFS_PARM4);
if (prinst->callargc >= 6)
pitchpct = G_FLOAT(OFS_PARM5);
else
pitchpct = 0;
pitchpct = (prinst->callargc>=6)?G_FLOAT(OFS_PARM5):0;
// flags = (prinst->callargc>=7)?G_FLOAT(OFS_PARM6):0;
startoffset = (prinst->callargc>=8)?G_FLOAT(OFS_PARM7):0;
sfx = S_PrecacheSound(sample);
if (sfx)
S_StartSound(-entity->entnum, channel, sfx, entity->v->origin, volume, attenuation, 0, pitchpct);
S_StartSound(-entity->entnum, channel, sfx, entity->v->origin, volume, attenuation, startoffset, pitchpct);
};
static void QCBUILTIN PF_cs_pointsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4015,13 +4097,15 @@ static void QCBUILTIN PF_cs_setlistener (pubprogfuncs_t *prinst, struct globalva
float *up = G_VECTOR(OFS_PARM3);
int inwater = (prinst->callargc>4)?G_FLOAT(OFS_PARM4):false;
r_refdef.audio.defaulted = false;
int i = (csqc_playerseat>=0)?csqc_playerseat:0;
cl.playerview[i].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;
VectorCopy(origin, cl.playerview[i].audio.origin);
VectorCopy(forward, cl.playerview[i].audio.forward);
VectorCopy(right, cl.playerview[i].audio.right);
VectorCopy(up, cl.playerview[i].audio.up);
cl.playerview[i].audio.inwater = inwater;
}
#define RSES_NOLERP 1
@ -4984,6 +5068,7 @@ static struct {
//230
{"strncasecmp", PF_strncasecmp, 230}, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
{"strtrim", PF_strtrim, 0},
{"calltimeofday", PF_calltimeofday, 231},
{"clientstat", PF_NoCSQC, 232}, // #231 clientstat
{"runclientphys", PF_NoCSQC, 233}, // #232 runclientphys
@ -5018,6 +5103,8 @@ static struct {
{"itos", PF_itos, 260},
{"stoh", PF_stoh, 261},
{"htos", PF_htos, 262},
{"ftoi", PF_ftoi, 0},
{"itof", PF_itof, 0},
{"skel_create", PF_skel_create, 263},//float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_build", PF_skel_build, 264},//float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addition) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS)
@ -5181,6 +5268,7 @@ static struct {
{"memgetval", PF_memgetval, 388},
{"memsetval", PF_memsetval, 389},
{"memptradd", PF_memptradd, 390},
{"memstrsize", PF_memstrsize, 0},
{"con_getset", PF_SubConGetSet, 391},
{"con_printf", PF_SubConPrintf, 392},
@ -5385,6 +5473,8 @@ static struct {
{"loadfromdata", PF_loadfromdata, 529},
{"loadfromfile", PF_loadfromfile, 530},
{"stopsound", PF_stopsound, 0},
{"soundupdate", PF_soundupdate, 0},
{"getsoundtime", PF_getsoundtime, 533},
{"soundlength", PF_soundlength, 534},
{"buf_loadfile", PF_buf_loadfile, 535},
@ -5603,7 +5693,7 @@ void CSQC_Event_Think(world_t *w, wedict_t *s)
PR_ExecuteProgram (w->progs, s->v->think);
}
void CSQC_Event_Sound (float *origin, wedict_t *wentity, int channel, const char *sample, int volume, float attenuation, int pitchadj)
void CSQC_Event_Sound (float *origin, wedict_t *wentity, int channel, const char *sample, int volume, float attenuation, int pitchadj, float timeoffset)
{
int i;
vec3_t originbuf;
@ -5619,7 +5709,7 @@ void CSQC_Event_Sound (float *origin, wedict_t *wentity, int channel, const char
origin = wentity->v->origin;
}
S_StartSound(NUM_FOR_EDICT(csqcprogs, (edict_t*)wentity), channel, S_PrecacheSound(sample), origin, volume, attenuation, 0, pitchadj);
S_StartSound(NUM_FOR_EDICT(csqcprogs, (edict_t*)wentity), channel, S_PrecacheSound(sample), origin, volume, attenuation, timeoffset, pitchadj);
}
qboolean CSQC_Event_ContentsTransition(world_t *w, wedict_t *ent, int oldwatertype, int newwatertype)
@ -5872,8 +5962,12 @@ pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc)
else
{
if (crc == 52195)
{
csqc_isdarkplaces = true;
Con_Printf(CON_WARNING "Running outdated or unknown csprogs.dat version\n");
Con_DPrintf(CON_WARNING "Running darkplaces csprogs.dat version\n");
}
else
Con_Printf(CON_WARNING "Running outdated or unknown csprogs.dat version\n");
}
}
return true;
@ -6057,9 +6151,9 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
}
if (csqc_isdarkplaces)
memset(&csqcg, 0, sizeof(csqcg));
CSQC_FindGlobals(true);
else
CSQC_FindGlobals();
CSQC_FindGlobals(false);
csqcentsize = PR_InitEnts(csqcprogs, pr_csqc_maxedicts.value);
@ -6136,7 +6230,7 @@ void CSQC_WorldLoaded(void)
return;
if (csqc_isdarkplaces)
CSQC_FindGlobals();
CSQC_FindGlobals(false);
csqcmapentitydataloaded = true;
csqcmapentitydata = cl.worldmodel->entities;
@ -6452,6 +6546,8 @@ qboolean CSQC_DrawView(void)
if (csqcg.frametime)
*csqcg.frametime = host_frametime;
csqc_dp_lastwas3d = false;
if (csqc_isdarkplaces && *csqc_world.g.physics_mode == 1)
{
csqc_world.physicstime = cl.servertime;
@ -6492,7 +6588,19 @@ qboolean CSQC_DrawView(void)
CSQC_ChangeLocalPlayer(cl_forceseat.ival?(cl_forceseat.ival - 1) % cl.splitclients:0);
if (csqcg.frametime)
*csqcg.frametime = host_frametime;
{
if (csqc_isdarkplaces)
{
static float oldtime;
if (cl.paused)
*csqcg.frametime = 0; //apparently people can't cope with microstutter when they're using this as a test to see if the game is paused.
else
*csqcg.frametime = bound(0, cl.time - oldtime, 0.1);
oldtime = cl.time;
}
else
*csqcg.frametime = host_frametime;
}
if (csqcg.numclientseats)
*csqcg.numclientseats = cl.splitclients;
@ -6575,6 +6683,7 @@ qboolean CSQC_DrawView(void)
qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid)
{
static qbyte csqckeysdown[K_MAX/8];
void *pr_globals;
#ifdef TEXTEDITOR
extern qboolean editormodal;
@ -6597,6 +6706,14 @@ qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid)
{
qcinput_scan = G_FLOAT(OFS_PARM1);
qcinput_unicode = G_FLOAT(OFS_PARM2);
csqckeysdown[key>>3] |= (1<<(key&7));
}
else
{
if (key && !(csqckeysdown[key>>3] & (1<<(key&7))))
return false;
csqckeysdown[key>>3] &= ~(1<<(key&7));
}
PR_ExecuteProgram (csqcprogs, csqcg.input_event);
qcinput_scan = 0; //and stop replay attacks
@ -6931,7 +7048,7 @@ static void CSQC_EntityCheck(unsigned int entnum)
}
}
int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod)
int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod, float timeofs)
{
void *pr_globals;
csqcedict_t *ent;
@ -6942,13 +7059,22 @@ int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float
{
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
CSQC_EntityCheck(entnum);
ent = csqcent[entnum];
if (ent)
*csqcg.self = EDICT_TO_PROG(csqcprogs, (void*)ent);
else
*csqcg.self = 0;
G_FLOAT(OFS_PARM0) = entnum;
G_FLOAT(OFS_PARM1) = channel;
G_INT(OFS_PARM2) = PR_TempString(csqcprogs, soundname);
G_FLOAT(OFS_PARM3) = vol;
G_FLOAT(OFS_PARM4) = attenuation;
VectorCopy(pos, G_VECTOR(OFS_PARM5));
G_FLOAT(OFS_PARM6) = attenuation;
G_FLOAT(OFS_PARM6) = pitchmod;
G_FLOAT(OFS_PARM7) = 0/*flags*/;
// G_FLOAT(OFS_PARM8) = timeofs;
PR_ExecuteProgram(csqcprogs, csqcg.event_sound);
@ -6969,6 +7095,8 @@ int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float
VectorCopy(pos, G_VECTOR(OFS_PARM2));
G_FLOAT(OFS_PARM3) = vol;
G_FLOAT(OFS_PARM4) = attenuation;
G_FLOAT(OFS_PARM5) = 0/*flags*/;
G_FLOAT(OFS_PARM6) = timeofs;
PR_ExecuteProgram(csqcprogs, csqcg.serversound);

View File

@ -12,6 +12,8 @@
qbyte mpkeysdown[K_MAX/8];
extern qboolean csqc_dp_lastwas3d;
extern unsigned int r2d_be_flags;
#define DRAWFLAG_NORMAL 0
#define DRAWFLAG_ADD 1
@ -19,6 +21,8 @@ extern unsigned int r2d_be_flags;
#define DRAWFLAG_MODULATE2 3
static unsigned int PF_SelectDPDrawFlag(int flag)
{
csqc_dp_lastwas3d = false; //for compat with dp's stupid beginpolygon
//flags:
//0 = blend
//1 = add
@ -51,6 +55,8 @@ void QCBUILTIN PF_CL_drawfill (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
srect_t srect;
csqc_dp_lastwas3d = false;
srect.x = G_FLOAT(OFS_PARM0) / (float)vid.width;
srect.y = (G_FLOAT(OFS_PARM1) / (float)vid.height);
srect.width = G_FLOAT(OFS_PARM2) / (float)vid.width;
@ -65,6 +71,8 @@ void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_
//void drawresetcliparea(void) = #459;
void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqc_dp_lastwas3d = false;
BE_Scissor(NULL);
G_FLOAT(OFS_RETURN) = 1;
}
@ -486,7 +494,10 @@ void QCBUILTIN PF_CL_drawpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
r2d_be_flags = PF_SelectDPDrawFlag(flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Image(pos[0], pos[1], size[0], size[1], 0, 0, 1, 1, p);
if ((size[0] < 0) ^ (size[1] < 0))
R2D_Image(pos[0]+size[0], pos[1]+size[1], -size[0], -size[1], 1, 1, 0, 0, p);
else
R2D_Image(pos[0], pos[1], size[0], size[1], 0, 0, 1, 1, p);
r2d_be_flags = 0;
}
@ -554,11 +565,10 @@ void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr
r2d_be_flags = PF_SelectDPDrawFlag(flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Image( pos[0], pos[1],
size[0], size[1],
srcPos[0], srcPos[1],
srcPos[0]+srcSize[0], srcPos[1]+srcSize[1],
p);
if ((size[0] < 0) ^ (size[1] < 0))
R2D_Image(pos[0]+size[0], pos[1]+size[1], -size[0], -size[1], srcPos[0]+srcSize[0], srcPos[1]+srcSize[1], srcPos[0], srcPos[1], p);
else
R2D_Image(pos[0], pos[1], size[0], size[1], srcPos[0], srcPos[1], srcPos[0]+srcSize[0], srcPos[1]+srcSize[1], p);
r2d_be_flags = 0;
G_FLOAT(OFS_RETURN) = 1;
@ -1872,6 +1882,14 @@ static struct {
{"vtos", PF_vtos, 19},
{"etos", PF_etos, 20},
{"stof", PF_stof, 21},
{"stoi", PF_stoi, 0},
{"itos", PF_itos, 0},
{"stoh", PF_stoh, 0},
{"htos", PF_htos, 0},
{"ftoi", PF_ftoi, 0},
{"itof", PF_itof, 0},
{"spawn", PF_Spawn, 22},
{"remove", PF_Remove_, 23},
{"find", PF_FindString, 24},
@ -1960,6 +1978,7 @@ static struct {
{"strncmp", PF_strncmp, 228},
{"strcasecmp", PF_strncasecmp, 229},
{"strncasecmp", PF_strncasecmp, 230},
{"strtrim", PF_strtrim, 0},
//gap
{"shaderforname", PF_shaderforname, 238},
//gap
@ -2008,6 +2027,7 @@ static struct {
{"memgetval", PF_memgetval, 388},
{"memsetval", PF_memsetval, 389},
{"memptradd", PF_memptradd, 390},
{"memstrsize", PF_memstrsize, 0},
{"con_getset", PF_SubConGetSet, 391},
{"con_printf", PF_SubConPrintf, 392},
{"con_draw", PF_SubConDraw, 393},
@ -2355,6 +2375,9 @@ qboolean MP_Init (void)
menuprogparms.user = &menu_world;
menu_world.keydestmask = kdm_gmenu;
//default to free mouse, to match dp's default setting, and because its generally the right thing for a menu.
key_dest_absolutemouse |= kdm_gmenu;
menutime = Sys_DoubleTime();
if (!menu_world.progs)
{

View File

@ -200,6 +200,51 @@ extern "C" {
#include <crtdbg.h>
#endif
//msvcrt lacks any and all c99 support.
#ifdef _WIN32
#define fPRIp "%p"
//totally different from any other system
#define fPRIllx "%I64x"
#define fPRIllu "%I64u"
#define fPRIlli "%I64i"
#else
//make SURE we get 0xdeadbeef for this
#if FTE_WORDSIZE != 32
#define fPRIp "%#zx"
#else
#define fPRIp "%#x"
#endif
//assume some c99 support where we print long long int types.
#define fPRIllx "%llx"
#define fPRIllu "%llu"
#define fPRIlli "%lli"
#endif
#ifdef _WIN32
//windows does not follow c99 at all
#ifdef _WIN64
#define fPRIzx "%Ix"
#define fPRIzu "%Iu"
#define fPRIzi "%Ii"
#else
#define fPRIzx "%x"
#define fPRIzu "%u"
#define fPRIzi "%i"
#endif
#elif FTE_WORDSIZE != 32
//64bit systems are expected to have an awareness of c99
#define fPRIzx "%zx"
#define fPRIzu "%zu"
#define fPRIzi "%zi"
#else
//regular old c89 for 32bit platforms.
#define fPRIzx "%x"
#define fPRIzu "%u"
#define fPRIzi "%i"
#endif
#ifdef _WIN32
#if (_MSC_VER >= 1400)
//with MSVC 8, use MS extensions

View File

@ -179,11 +179,9 @@ void R2D_Init(void)
nogloss[i] = glossval;
nonorm[i] = normval;
}
missing_texture = R_LoadHiResTexture("no_texture", NULL, IF_NEAREST|IF_NOWORKER);
if (!TEXLOADED(missing_texture))
missing_texture = R_LoadTexture8("no_texture", 16, 16, (unsigned char*)(r_notexture_mip+1), IF_NOALPHA|IF_NOGAMMA, 0);
missing_texture_gloss = R_LoadTexture("no_texture_gloss", 4, 4, TF_RGBA32, (unsigned char*)nogloss, IF_NOGAMMA);
missing_texture_normal = R_LoadTexture("no_texture_normal", 4, 4, TF_RGBA32, (unsigned char*)nonorm, IF_NOGAMMA);
missing_texture = R_LoadTexture8("no_texture", 16, 16, (unsigned char*)(r_notexture_mip+1), IF_NOALPHA|IF_NOGAMMA|IF_NOPURGE, 0);
missing_texture_gloss = R_LoadTexture("no_texture_gloss", 4, 4, TF_RGBA32, (unsigned char*)nogloss, IF_NOGAMMA|IF_NOPURGE);
missing_texture_normal = R_LoadTexture("no_texture_normal", 4, 4, TF_RGBA32, (unsigned char*)nonorm, IF_NOGAMMA|IF_NOPURGE);
translate_texture = r_nulltex;
ch_int_texture = r_nulltex;

View File

@ -47,7 +47,7 @@ typedef struct
size_t numsoups;
} cluttersector_t;
static cluttersector_t cluttersector[3*3*3];
cvar_t r_clutter_density = CVARD("r_clutter_density", "1", "Scaler for clutter counts. 0 disables clutter completely.\nClutter requires shaders with 'fte_clutter MODEL SPACING SCALEMIN SCALEMAX ZOFS ANGLEMIN ANGLEMAX' terms");
cvar_t r_clutter_density = CVARD("r_clutter_density", "0", "Scaler for clutter counts. 0 disables clutter completely.\nClutter requires shaders with 'fte_clutter MODEL SPACING SCALEMIN SCALEMAX ZOFS ANGLEMIN ANGLEMAX' terms");
cvar_t r_clutter_distance = CVARD("r_clutter_distance", "1024", "Distance at which clutter will become invisible."); //should be used by various shaders to fade it out by here
void R_Clutter_Init(void)
{
@ -616,6 +616,9 @@ cvar_t r_part_classic_expgrav = CVARFD("r_part_classic_expgrav", "10", CVAR_ARCH
particleengine_t *pe;
void P_ParticleEffect_f(void);
static void P_ParticleEffectAlias_f(void);
void P_InitParticleSystem(void)
{
char *particlecvargroupname = "Particle effects";
@ -644,9 +647,92 @@ void P_InitParticleSystem(void)
Cvar_Register (&r_rockettrail, particlecvargroupname);
Cvar_Register (&r_grenadetrail, particlecvargroupname);
//always registered to suck up stray r_part commands even when the scripted system is not active.
#ifdef PSET_SCRIPT
Cmd_AddCommand("r_part", P_ParticleEffect_f);
#endif
Cmd_AddCommand("r_partredirect", P_ParticleEffectAlias_f);
R_Clutter_Init();
}
static struct partalias_s
{
struct partalias_s *next;
const char *from;
const char *to;
} *partaliaslist;
static void P_ParticleEffectAlias_f(void)
{
struct partalias_s **link, *l;
char *from = Cmd_Argv(1);
char *to = Cmd_Argv(2);
//user wants to list all
if (!*from)
{
for (l = partaliaslist; l; l = l->next)
{
Con_Printf("%s -> %s\n", l->from, l->to);
}
return;
}
//unlink the current value
for (link = &partaliaslist; (l=*link); link = &(*link)->next)
{
if (!Q_strcasecmp(l->from, from))
{
//they didn't specify a to, so just print out this one effect without removing it.
if (Cmd_Argc() == 2)
{
Con_Printf("particle %s is currently remapped to %s\n", l->from, l->to);
return;
}
*link = l->next;
Z_Free(l);
break;
}
}
//create a new entry.
if (*to && Q_strcasecmp(from, to))
{
l = Z_Malloc(sizeof(*l) + strlen(from) + strlen(to) + 2);
l->from = (char*)(l + 1);
strcpy((char*)l->from, from);
l->to = l->from + strlen(l->from)+1;
strcpy((char*)l->to, to);
l->next = partaliaslist;
partaliaslist = l;
}
CL_RegisterParticles();
}
int P_FindParticleType(const char *efname)
{
struct partalias_s *l;
int recurselimit = 5;
if (!pe)
return P_INVALID;
for (l = partaliaslist; l; )
{
if (!Q_strcasecmp(l->from, efname))
{
efname = l->to;
if (recurselimit --> 0)
l = partaliaslist;
else
return P_INVALID;
}
else
l = l->next;
}
return pe->FindParticleType(efname);
}
void P_Shutdown(void)
{
if (pe)

View File

@ -36,10 +36,9 @@ model_t *currentmodel;
int lightmap_bytes; // 1, 3 or 4
qboolean lightmap_bgra;
#define MAX_LIGHTMAP_SIZE 1024//LMBLOCK_WIDTH
vec3_t blocknormals[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE];
unsigned blocklights[3*MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE];
size_t maxblocksize;
vec3_t *blocknormals;
unsigned *blocklights;
lightmapinfo_t **lightmap;
int numlightmaps;
@ -874,7 +873,8 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest,
{
int smax, tmax;
int t;
int i, j, size;
int i, j;
size_t size;
qbyte *lightmap;
unsigned scale;
int maps;
@ -887,13 +887,17 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest,
smax = (surf->extents[0]>>surf->lmshift)+1;
tmax = (surf->extents[1]>>surf->lmshift)+1;
size = smax*tmax;
size = (size_t)smax*tmax;
lightmap = surf->samples;
if (size > MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE)
if (size > maxblocksize)
{ //fixme: fill in?
Con_Printf("Lightmap too large\n");
return;
BZ_Free(blocklights);
BZ_Free(blocknormals);
maxblocksize = size;
blocknormals = BZ_Malloc(maxblocksize * sizeof(*blocknormals)); //already a vector
blocklights = BZ_Malloc(maxblocksize * 3*sizeof(*blocklights));
}
if (currentmodel->deluxdata)
@ -2136,18 +2140,18 @@ void Surf_SetupFrame(void)
V_SetContentsColor (r_viewcontents);
if (r_refdef.audio.defaulted)
if (r_refdef.playerview->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_refdef.vieworg, r_refdef.audio.origin);
VectorCopy(vpn, r_refdef.audio.forward);
VectorCopy(vright, r_refdef.audio.right);
VectorCopy(vup, r_refdef.audio.up);
r_refdef.playerview->audio.defaulted = false;
VectorCopy(r_refdef.vieworg, r_refdef.playerview->audio.origin);
VectorCopy(vpn, r_refdef.playerview->audio.forward);
VectorCopy(vright, r_refdef.playerview->audio.right);
VectorCopy(vup, r_refdef.playerview->audio.up);
if (r_viewcontents & FTECONTENTS_FLUID)
r_refdef.audio.inwater = true;
r_refdef.playerview->audio.inwater = true;
else
r_refdef.audio.inwater = false;
r_refdef.playerview->audio.inwater = false;
}
}
@ -2451,6 +2455,7 @@ void Surf_DeInit(void)
void Surf_Clear(model_t *mod)
{
int i;
vbo_t *vbo;
if (mod->fromgame == fg_doom3)
return;/*they're on the hunk*/
@ -2461,12 +2466,29 @@ void Surf_Clear(model_t *mod)
BE_ClearVBO(vbo);
}
if (!mod->submodelof)
{
for (i = 0; i < mod->numtextures; i++)
{
R_UnloadShader(mod->textures[i]->shader);
mod->textures[i]->shader = NULL;
}
}
mod->numtextures = 0;
BZ_Free(mod->shadowbatches);
mod->numshadowbatches = 0;
mod->shadowbatches = NULL;
#ifdef RTLIGHTS
Sh_PurgeShadowMeshes();
#endif
BZ_Free(blocklights);
BZ_Free(blocknormals);
blocklights = NULL;
blocknormals = NULL;
maxblocksize = 0;
}
//pick fastest mode for lightmap data
@ -2953,6 +2975,11 @@ TRACE(("dbg: Surf_NewMap: tp\n"));
//fixme: no rotation
if (cl_static_entities[i].ent.model)
{
//unfortunately, we need to know the actual size so that we can get this right. bum.
if (cl_static_entities[i].ent.model->loadstate == MLS_NOTLOADED)
Mod_LoadModel(cl_static_entities[i].ent.model, MLV_SILENT);
if (cl_static_entities[i].ent.model->loadstate == MLS_LOADING)
COM_WorkerPartialSync(cl_static_entities[i].ent.model, &cl_static_entities[i].ent.model->loadstate, MLS_LOADING);
VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->mins, mins);
VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->maxs, maxs);
}

View File

@ -37,7 +37,11 @@ struct texture_s;
static const texid_t r_nulltex = NULL;
//GLES2 requires GL_UNSIGNED_SHORT
//geforce4 only does shorts. gffx can do ints, but with a performance hit (like most things on that gpu)
//ati is generally more capable, but generally also has a smaller market share
//desktop-gl will generally cope with ints, but expect a performance hit from that (so we don't bother)
//dx10 can cope with ints,
#if 1 || defined(MINIMAL) || defined(D3DQUAKE) || defined(ANDROID)
#define sizeof_index_t 2
#endif
@ -196,7 +200,7 @@ typedef struct
float time; //timestamp for when its current.
} fogstate_t;
void CL_BlendFog(fogstate_t *result, fogstate_t *oldf, float time, fogstate_t *newf);
void CL_ResetFog(void);
void CL_ResetFog(int fogtype);
typedef struct {
char texname[MAX_QPATH];
@ -254,16 +258,6 @@ typedef struct
qbyte *forcedvis;
qboolean areabitsknown;
qbyte areabits[MAX_MAP_AREA_BYTES];
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;
@ -373,6 +367,8 @@ enum imageflags
IF_TEXTYPESHIFT = 8, /*0=2d, 1=3d, 2-7=cubeface*/
IF_MIPCAP = 1<<10,
IF_PREMULTIPLYALPHA = 1<<12, //rgb *= alpha
IF_NOPURGE = 1<<22,
IF_HIGHPRIORITY = 1<<23,
IF_LOWPRIORITY = 1<<24,
IF_LOADNOW = 1<<25, /*hit the disk now, and delay the gl load until its actually needed. this is used only so that the width+height are known in advance*/
@ -395,6 +391,7 @@ image_t *Image_GetTexture (const char *identifier, const char *subpath, unsigned
qboolean Image_UnloadTexture(image_t *tex); //true if it did something.
void Image_DestroyTexture (image_t *tex);
void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags);
void Image_Purge(void); //purge any textures which are not needed any more (releases memory, but doesn't give null pointers).
void Image_Init(void);
void Image_Shutdown(void);

View File

@ -67,9 +67,9 @@ cvar_t mod_md3flags = CVARD ("mod_md3flags", "1", "The flags field of md3
cvar_t r_ambient = CVARF ("r_ambient", "0",
CVAR_CHEAT);
cvar_t r_bloodstains = CVARF ("r_bloodstains", "1", CVAR_ARCHIVE);
cvar_t r_bouncysparks = CVARFD ("r_bouncysparks", "0",
cvar_t r_bouncysparks = CVARFD ("r_bouncysparks", "1",
CVAR_ARCHIVE,
"Enables particle interaction with world surfaces, allowing for bouncy particles.");
"Enables particle interaction with world surfaces, allowing for bouncy particles, stains, and decals.");
cvar_t r_drawentities = CVAR ("r_drawentities", "1");
cvar_t r_drawflat = CVARF ("r_drawflat", "0",
CVAR_ARCHIVE | CVAR_SEMICHEAT | CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM);
@ -2640,7 +2640,7 @@ void R_InitParticleTexture (void)
data[y*32+x][3] = 255;
}
}
particlecqtexture = R_LoadTexture32("classicparticle", 32, 32, data, IF_NOMIPMAP|IF_NOPICMIP);
particlecqtexture = Image_GetTexture("classicparticle", "particles", IF_NOMIPMAP|IF_NOPICMIP, data, NULL, 32, 32, TF_RGBA32);
//draw a square in the top left. still a triangle.
for (x=0 ; x<16 ; x++)
@ -2650,8 +2650,7 @@ void R_InitParticleTexture (void)
data[y*32+x][3] = 255;
}
}
R_LoadTexture32("classicparticle_square", 32, 32, data, IF_NOMIPMAP|IF_NOPICMIP);
Image_GetTexture("classicparticle_square", "particles", IF_NOMIPMAP|IF_NOPICMIP, data, NULL, 32, 32, TF_RGBA32);
for (x=0 ; x<16 ; x++)
@ -2664,7 +2663,7 @@ void R_InitParticleTexture (void)
data[y*16+x][3] = exptexture[x][y]*255/9.0;
}
}
explosiontexture = R_LoadTexture32("fte_fuzzyparticle", 16, 16, data, IF_NOMIPMAP|IF_NOPICMIP);
explosiontexture = Image_GetTexture("fte_fuzzyparticle", "particles", IF_NOMIPMAP|IF_NOPICMIP, data, NULL, 16, 16, TF_RGBA32);
for (x=0 ; x<16 ; x++)
{
@ -2676,7 +2675,19 @@ void R_InitParticleTexture (void)
data[y*16+x][3] = exptexture[x][y]*255/9.0;
}
}
R_LoadTexture32("fte_bloodparticle", 16, 16, data, IF_NOMIPMAP|IF_NOPICMIP);
Image_GetTexture("fte_bloodparticle", "particles", IF_NOMIPMAP|IF_NOPICMIP, data, NULL, 16, 16, TF_RGBA32);
for (x=0 ; x<16 ; x++)
{
for (y=0 ; y<16 ; y++)
{
data[y*16+x][0] = min(255, exptexture[x][y]*255/9.0);
data[y*16+x][1] = min(255, exptexture[x][y]*255/5.0);
data[y*16+x][2] = min(255, exptexture[x][y]*255/5.0);
data[y*16+x][3] = 255;
}
}
Image_GetTexture("fte_blooddecal", "particles", IF_NOMIPMAP|IF_NOPICMIP, data, NULL, 16, 16, TF_RGBA32);
memset(data, 255, sizeof(data));
for (y = 0;y < PARTICLETEXTURESIZE;y++)

View File

@ -643,7 +643,7 @@ void Sbar_ExecuteLayoutString (char *s)
static void Sbar_Q2DrawInventory(void)
{
int keys[2];
int keys[1], keymods[1];
char cmd[1024];
const char *boundkey;
unsigned int validlist[Q2MAX_ITEMS], rows, i, item, selected = cl.q2frame.playerstate.stats[Q2STAT_SELECTED_ITEM];
@ -679,11 +679,10 @@ static void Sbar_Q2DrawInventory(void)
item = validlist[i];
Q_snprintfz(cmd, sizeof(cmd), "use %s", Get_Q2ConfigString(Q2CS_ITEMS+item));
M_FindKeysForCommand(0, cmd, keys);
if (keys[0] == -1)
if (!M_FindKeysForCommand(0, 0, cmd, keys, keymods, countof(keys)))
boundkey = ""; //we don't actually know which ones can be selected at all.
else
boundkey = Key_KeynumToString(keys[0]);
boundkey = Key_KeynumToString(keys[0], keymods[0]);
Q_snprintfz(cmd, sizeof(cmd), "%6s %3i %s", boundkey, cl.inventory[item], Get_Q2ConfigString(Q2CS_ITEMS+item));
Draw_FunStringWidth(x, y, cmd, 256-24*2+8, false, item != selected); y+=8;
@ -1144,6 +1143,8 @@ void Draw_TinyString (float x, float y, const qbyte *str)
{
float xstart;
int px, py;
unsigned int codepoint;
int error;
if (!font_tiny)
{
@ -1157,15 +1158,16 @@ void Draw_TinyString (float x, float y, const qbyte *str)
while (*str)
{
if (*str == '\n')
codepoint = unicode_decode(&error, str, (char**)&str, true);
if (codepoint == '\n')
{
px = xstart;
py += Font_CharHeight();
str++;
continue;
}
//fixme: utf-8 encoding.
px = Font_DrawChar(px, py, CON_WHITEMASK, *str++);
px = Font_DrawChar(px, py, CON_WHITEMASK, codepoint);
}
Font_EndString(font_tiny);
}

View File

@ -56,7 +56,7 @@ void RSpeedShow(void);
void SCR_CrosshairPosition(playerview_t *pview, float *x, float *y);
void SCR_DrawLoading (qboolean opaque);
void SCR_TileClear (void);
void SCR_TileClear (int skipbottom);
void SCR_DrawNotifyString (void);
void SCR_CheckDrawCenterString (void);
void SCR_DrawNet (void);

View File

@ -554,7 +554,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
}
if (!schanged && sfx
#ifndef FTE_TARGET_WEB
&& (chan->looping || (!sfx->decoder.decodedata && sfx->decoder.buf && ((sfxcache_t*)sfx->decoder.buf)->loopstart))
&& ((chan->flags & CF_FORCELOOP) || (!sfx->decoder.decodedata && sfx->decoder.buf && ((sfxcache_t*)sfx->decoder.buf)->loopstart))
#endif
)
{
@ -562,7 +562,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
if (buf != AL_PLAYING)
{
schanged = true;
if (chan->looping)
if (chan->flags & CF_FORCELOOP)
chan->pos = 0;
else
sfx = chan->sfx = NULL;
@ -625,7 +625,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
palGetSourcei(src, AL_SOURCE_STATE, &buf);
if (buf != AL_PLAYING)
{
if (chan->looping)
if (chan->flags & CF_FORCELOOP)
chan->pos = 0;
else if(sbuf.loopstart != -1)
chan->pos = sbuf.loopstart<<PITCHSHIFT;
@ -696,7 +696,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
palSource3i(src, AL_AUXILIARY_SEND_FILTER, oali->effectslot, 0, AL_FILTER_NULL);
#endif
palSourcei(src, AL_LOOPING, chan->looping?AL_TRUE:AL_FALSE);
palSourcei(src, AL_LOOPING, (chan->flags & CF_FORCELOOP)?AL_TRUE:AL_FALSE);
if (chan->entnum == -1 || chan->entnum == cl.playerview[0].viewentity)
{
palSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);

View File

@ -43,11 +43,15 @@ static qboolean snd_ambient = 1;
qboolean snd_initialized = false;
int snd_speed;
vec3_t listener_origin;
vec3_t listener_forward = {1, 0, 0};
vec3_t listener_right = {0, 1, 0};
vec3_t listener_up = {0, 0, 1};
vec3_t listener_velocity;
static struct
{
int entnum;
vec3_t origin;
vec3_t velocity;
vec3_t forward;
vec3_t right;
vec3_t up;
} listener[MAX_SPLITS];
vec_t sound_nominal_clip_dist=1000.0;
#define MAX_SFX 8192
@ -1483,7 +1487,12 @@ void S_DefaultSpeakerConfiguration(soundcardinfo_t *sc)
}
sounddriver_t DSOUND_Output;
#ifdef AVAIL_XAUDIO2
extern sounddriver_t XAUDIO2_Output;
#endif
#ifdef AVAIL_DSOUND
extern sounddriver_t DSOUND_Output;
#endif
sounddriver_t SDL_Output;
sounddriver_t ALSA_Output;
sounddriver_t OSS_Output;
@ -1506,11 +1515,15 @@ extern sounddriver pPPAPI_InitCard;
sounddriver_t *outputdrivers[] =
{
#ifdef AVAIL_OPENAL
&OPENAL_Output,
&OPENAL_Output, //refuses to run as the default device, at least until its perfected.
#endif
#ifdef _WIN32
#ifdef AVAIL_DSOUND
&DSOUND_Output,
#endif
#ifdef AVAIL_XAUDIO2
&XAUDIO2_Output,
#endif
&SDL_Output, //prefered on linux
#ifdef __linux__
@ -1537,7 +1550,7 @@ sdriver_t olddrivers[] = {
{NULL, NULL}
};
static soundcardinfo_t *SNDDMA_Init(char *driver, char *device)
static soundcardinfo_t *SNDDMA_Init(char *driver, char *device, int seat)
{
soundcardinfo_t *sc = Z_Malloc(sizeof(soundcardinfo_t));
sdriver_t *od;
@ -1546,6 +1559,7 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device)
int st;
memset(sc, 0, sizeof(*sc));
sc->seat = seat;
// set requested rate
if (snd_khz.ival >= 1000)
@ -1661,6 +1675,17 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device)
return NULL;
}
void S_SetupDeviceSeat(char *driver, char *device, int seat)
{
SNDDMA_Init(driver, device, seat);
/*
soundcardinfo_t *sc;
for (sc = sndcardinfo; sc; sc = sc->next)
{
sc->seat = seat;
}*/
}
void QDECL S_EnumeratedOutDevice(const char *driver, const char *devicecode, const char *readabledevice)
{
const char *fullintname;
@ -1732,11 +1757,17 @@ void S_Startup (void)
sep = strchr(com_token, ':');
if (sep)
*sep++ = 0;
SNDDMA_Init(com_token, sep);
SNDDMA_Init(com_token, sep, 0);
}
}
if (!sndcardinfo && !nodefault)
SNDDMA_Init(NULL, NULL);
{
#ifdef _WIN32
INS_SetupControllerAudioDevices();
#endif
if (!sndcardinfo)
SNDDMA_Init(NULL, NULL, 0);
}
sound_started = true;
@ -1752,15 +1783,6 @@ void S_Startup (void)
ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");
}
void S_SetUnderWater(qboolean underwater)
{
soundcardinfo_t *sc;
for (sc = sndcardinfo; sc; sc=sc->next)
if (sc->SetWaterDistortion)
sc->SetWaterDistortion(sc, underwater);
}
//why isn't this part of S_Restart_f anymore?
//so that the video code can call it directly without flushing the models it's just loaded.
void S_DoRestart (void)
@ -2200,7 +2222,7 @@ channel_t *SND_PickChannel(soundcardinfo_t *sc, int entnum, int entchannel)
}
// don't let monster sounds override player sounds
if (sc->channel[ch_idx].entnum == cl.playerview[0].playernum+1 && entnum != cl.playerview[0].playernum+1 && sc->channel[ch_idx].sfx)
if (sc->channel[ch_idx].entnum == listener[sc->seat].entnum && entnum != listener[sc->seat].entnum && sc->channel[ch_idx].sfx)
continue;
if (!sc->channel[ch_idx].sfx)
@ -2261,14 +2283,14 @@ void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch)
}
// calculate stereo seperation and distance attenuation
VectorSubtract(ch->origin, listener_origin, world_vec);
VectorSubtract(ch->origin, listener[sc->seat].origin, world_vec);
dist = VectorNormalize(world_vec) * ch->dist_mult;
//rotate the world_vec into listener space, so that the audio direction stored in the speakerdir array can be used directly.
listener_vec[0] = DotProduct(listener_forward, world_vec);
listener_vec[1] = DotProduct(listener_right, world_vec);
listener_vec[2] = DotProduct(listener_up, world_vec);
listener_vec[0] = DotProduct(listener[sc->seat].forward, world_vec);
listener_vec[1] = DotProduct(listener[sc->seat].right, world_vec);
listener_vec[2] = DotProduct(listener[sc->seat].up, world_vec);
if (snd_leftisright.ival)
listener_vec[1] = -listener_vec[1];
@ -2285,22 +2307,24 @@ void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch)
// =======================================================================
// Start a sound effect
// =======================================================================
static void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, int startpos, float pitchadj)
static void S_UpdateSoundCard(soundcardinfo_t *sc, qboolean updateonly, channel_t *target_chan, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float timeoffset, float pitchadj)
{
channel_t *target_chan, *check;
channel_t *check;
int vol;
int ch_idx;
int skip;
int entnum = target_chan->entnum;
int entchannel = target_chan->entchannel;
int absstartpos = updateonly?target_chan->pos:0;
if (!sound_started)
if (fvol < 0)
{ //stopsound, apparently.
target_chan->sfx = NULL;
return;
}
if (!sfx)
return;
if (nosound.ival)
return;
sfx = target_chan->sfx;
if (pitchadj <= 0)
pitchadj = 100;
@ -2309,16 +2333,11 @@ static void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sf
vol = fvol*255;
// pick a channel to play on
target_chan = SND_PickChannel(sc, entnum, entchannel);
if (!target_chan)
return;
// spatialize
memset (target_chan, 0, sizeof(*target_chan));
if (!origin)
{
VectorCopy(listener_origin, target_chan->origin);
VectorCopy(listener[sc->seat].origin, target_chan->origin);
}
else
{
@ -2331,35 +2350,43 @@ static void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sf
target_chan->entchannel = entchannel;
SND_Spatialize(sc, target_chan);
if (!target_chan->vol[0] && !target_chan->vol[1] && !target_chan->vol[2] && !target_chan->vol[3] && !target_chan->vol[4] && !target_chan->vol[5] && sc->ChannelUpdate)
return; // not audible at all
// new channel
if (!S_LoadSound (sfx))
if (!updateonly && !target_chan->vol[0] && !target_chan->vol[1] && !target_chan->vol[2] && !target_chan->vol[3] && !target_chan->vol[4] && !target_chan->vol[5] && sc->ChannelUpdate)
{
target_chan->sfx = NULL;
return; // couldn't load the sound's data
return; // not audible at all
}
if (sfx)
{
if (!S_LoadSound (sfx))
{
target_chan->sfx = NULL;
return; // couldn't load the sound's data
}
target_chan->sfx = sfx;
}
target_chan->sfx = sfx;
target_chan->rate = ((1<<PITCHSHIFT) * pitchadj) / 100; /*pitchadj is a percentage*/
if (target_chan->rate < 1) /*make sure the rate won't crash us*/
target_chan->rate = 1;
target_chan->pos = startpos*target_chan->rate;
target_chan->looping = false;
target_chan->pos = absstartpos + (int)(timeoffset*sc->sn.speed*target_chan->rate);
if (!updateonly)
{
// if an identical sound has also been started this frame, offset the pos
// a bit to keep it from just making the first one louder
check = &sc->channel[DYNAMIC_FIRST];
for (ch_idx=DYNAMIC_FIRST; ch_idx < DYNAMIC_STOP; ch_idx++, check++)
{
if (check == target_chan)
continue;
if (check->sfx == sfx && !check->pos)
check = &sc->channel[DYNAMIC_FIRST];
for (ch_idx=DYNAMIC_FIRST; ch_idx < DYNAMIC_STOP; ch_idx++, check++)
{
skip = rand () % (int)(0.1*sc->sn.speed);
target_chan->pos -= skip*target_chan->rate;
break;
if (check == target_chan)
continue;
if (check->sfx == sfx && !check->pos)
{
skip = rand () % (int)(0.1*sc->sn.speed);
target_chan->pos -= skip*target_chan->rate;
break;
}
}
}
@ -2367,9 +2394,39 @@ static void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sf
sc->ChannelUpdate(sc, target_chan, true);
}
float S_UpdateSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float timeofs, float pitchadj)
{
int i;
int result = 0;
int cards = 0;
soundcardinfo_t *sc;
if (cls.demoseeking)
return result;
S_LockMixer();
for (sc = sndcardinfo; sc; sc = sc->next)
{
cards++;
for (i = 0; i < sc->total_chans; i++)
{
if (sc->channel[i].entnum == entnum && sc->channel[i].entchannel == entchannel && sc->channel[i].sfx)
{
S_UpdateSoundCard(sc, true, &sc->channel[i], sfx, origin, fvol, attenuation, timeofs, pitchadj);
result++;
break;
}
}
}
S_UnlockMixer();
if (!cards)
cards=1;
return result / (float)cards;
}
void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float timeofs, float pitchadj)
{
soundcardinfo_t *sc;
channel_t *target_chan;
if (!sfx || !*sfx->name) //no named sounds would need specific starting.
return;
@ -2377,9 +2434,22 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
if (cls.demoseeking)
return;
if (!sound_started)
return;
if (nosound.ival)
return;
S_LockMixer();
for (sc = sndcardinfo; sc; sc = sc->next)
S_StartSoundCard(sc, entnum, entchannel, sfx, origin, fvol, attenuation, -(int)(timeofs * sc->sn.speed), pitchadj);
{
// pick a channel to play on
target_chan = SND_PickChannel(sc, entnum, entchannel);
if (!target_chan)
return;
S_UpdateSoundCard(sc, false, target_chan, sfx, origin, fvol, attenuation, timeofs, pitchadj);
}
S_UnlockMixer();
}
@ -2604,7 +2674,7 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
ss->master_vol = vol;
ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;
ss->pos = 0;
ss->looping = true;
ss->flags = CF_FORCELOOP;
SND_Spatialize (scard, ss);
@ -2699,30 +2769,12 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
{
qboolean changed = false;
chan = &sc->channel[i];
if (!chan->sfx)
{
char *nexttrack = Media_NextTrack(i-MUSIC_FIRST);
sfx_t *newmusic;
if (nexttrack && *nexttrack)
{
newmusic = S_PrecacheSound(nexttrack);
if (newmusic && newmusic->loadstate != SLS_FAILED)
{
chan->sfx = newmusic;
chan->rate = 1<<PITCHSHIFT;
chan->pos = 0;
changed = true;
}
}
}
if (chan->sfx)
{
chan->flags = CF_ABSVOLUME; //bypasses volume cvar completely.
vol = 255*bgmvolume.value*voicevolumemod;
vol = bound(0, vol, 255);
vol = Media_CrossFade(i-MUSIC_FIRST, vol);
vol = Media_CrossFade(i-MUSIC_FIRST, vol, (chan->pos>>PITCHSHIFT) / (float)snd_speed);
if (vol < 0)
{ //cross fading wants to KILL this track now, apparently.
sfx_t *s = chan->sfx;
@ -2738,12 +2790,33 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
if (s && s->decoder.ended && !S_IsPlayingSomewhere(s)) //if we aint playing it elsewhere, free it compleatly.
s->decoder.ended(s);
}
continue;
}
chan->master_vol = bound(0, vol, 255);
chan->vol[0] = chan->vol[1] = chan->vol[2] = chan->vol[3] = chan->vol[4] = chan->vol[5] = chan->master_vol;
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, chan, changed);
else
{
chan->master_vol = bound(0, vol, 255);
chan->vol[0] = chan->vol[1] = chan->vol[2] = chan->vol[3] = chan->vol[4] = chan->vol[5] = chan->master_vol;
if (sc->ChannelUpdate)
sc->ChannelUpdate(sc, chan, changed);
}
}
if (!chan->sfx)
{
float time = 0;
char *nexttrack = Media_NextTrack(i-MUSIC_FIRST, &time);
sfx_t *newmusic;
if (nexttrack && *nexttrack)
{
newmusic = S_PrecacheSound(nexttrack);
if (newmusic && newmusic->loadstate != SLS_FAILED)
{
chan->sfx = newmusic;
chan->rate = 1<<PITCHSHIFT;
chan->pos = (int)(time * sc->sn.speed) * chan->rate;
changed = true;
}
}
}
}
@ -2752,7 +2825,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
if (!cl.worldmodel || cl.worldmodel->type != mod_brush || cl.worldmodel->fromgame != fg_quake || cl.worldmodel->loadstate != MLS_LOADED)
return;
l = Q1BSP_LeafForPoint(cl.worldmodel, listener_origin);
l = Q1BSP_LeafForPoint(cl.worldmodel, listener[sc->seat].origin);
if (!l || ambient_level.value <= 0)
{
for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
@ -2771,10 +2844,10 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
chan = &sc->channel[AMBIENT_FIRST+ambient_channel];
chan->sfx = ambient_sfx[AMBIENT_FIRST+ambient_channel];
chan->entnum = -1;
chan->looping = true;
chan->flags = CF_FORCELOOP;
chan->rate = 1<<PITCHSHIFT;
VectorCopy(listener_origin, chan->origin);
VectorCopy(listener[sc->seat].origin, chan->origin);
vol = ambient_level.value * l->ambient_sound_level[ambient_channel];
if (vol < 8)
@ -2811,20 +2884,26 @@ S_Update
Called once each time through the main loop
============
*/
void S_UpdateListener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
void S_UpdateListener(int seat, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, qboolean underwater)
{
VectorCopy(origin, listener_origin);
VectorCopy(forward, listener_forward);
VectorCopy(right, listener_right);
VectorCopy(up, listener_up);
soundcardinfo_t *sc;
listener[seat].entnum = cl.playerview[seat].playernum+1;
VectorCopy(origin, listener[seat].origin);
VectorCopy(forward, listener[seat].forward);
VectorCopy(right, listener[seat].right);
VectorCopy(up, listener[seat].up);
for (sc = sndcardinfo; sc; sc=sc->next)
if (sc->SetWaterDistortion && sc->seat == seat)
sc->SetWaterDistortion(sc, underwater);
}
void S_GetListenerInfo(float *origin, float *forward, float *right, float *up)
void S_GetListenerInfo(int seat, float *origin, float *forward, float *right, float *up)
{
VectorCopy(listener_origin, origin);
VectorCopy(listener_forward, forward);
VectorCopy(listener_right, right);
VectorCopy(listener_up, up);
VectorCopy(listener[seat].origin, origin);
VectorCopy(listener[seat].forward, forward);
VectorCopy(listener[seat].right, right);
VectorCopy(listener[seat].up, up);
}
static void S_UpdateCard(soundcardinfo_t *sc)
@ -2845,7 +2924,7 @@ static void S_UpdateCard(soundcardinfo_t *sc)
#ifdef AVAIL_OPENAL
if (sc->ListenerUpdate)
{
sc->ListenerUpdate(sc, listener_origin, listener_forward, listener_right, listener_up, listener_velocity);
sc->ListenerUpdate(sc, listener[sc->seat].origin, listener[sc->seat].forward, listener[sc->seat].right, listener[sc->seat].up, listener[sc->seat].velocity);
}
#endif
@ -2951,7 +3030,8 @@ int S_GetMixerTime(soundcardinfo_t *sc)
// calls to S_Update. Oh well.
samplepos = sc->GetDMAPos(sc);
samplepos -= sc->samplequeue;
if (sc->samplequeue > 0)
samplepos -= sc->samplequeue;
if (samplepos < 0)
{
@ -3028,13 +3108,19 @@ static void S_Update_(soundcardinfo_t *sc)
// Updates DMA time
soundtime = S_GetMixerTime(sc);
if (sc->samplequeue)
if (sc->samplequeue > 0)
{
/*device uses a write-once queue*/
endtime = soundtime + sc->samplequeue/sc->sn.numchannels;
soundtime = sc->paintedtime;
samps = sc->samplequeue / sc->sn.numchannels;
}
else if (sc->samplequeue < 0)
{
endtime = soundtime;
soundtime = sc->paintedtime;
samps = sc->sn.samples / sc->sn.numchannels;
}
else
{
/*device uses memory-mapped output*/
@ -3228,7 +3314,7 @@ void S_ClearRaw(void)
}
//returns an sfxcache_t stating where the data is
sfxcache_t *S_Raw_Locate(sfx_t *sfx, sfxcache_t *buf, int start, int length)
sfxcache_t *S_Raw_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start, int length)
{
streaming_t *s = sfx->decoder.buf;
if (buf)
@ -3405,7 +3491,6 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
c->entnum = -1;
c->entchannel = 0;
c->dist_mult = 0;
c->looping = false;
c->master_vol = 255 * volume;
c->pos = 0;
c->rate = 1<<PITCHSHIFT;

View File

@ -824,7 +824,7 @@ void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
result = VFS_READ(f, data, filesize);
if (result != filesize)
Con_SafePrintf("S_LoadSound() fread: Filename: %s, expected %i, result was %u\n", name, filesize, (unsigned int)result);
Con_SafePrintf("S_LoadSound() fread: Filename: %s, expected "fPRIzu", result was "fPRIzu"\n", name, filesize, result);
VFS_CLOSE(f);
}

View File

@ -159,7 +159,7 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
ch->pos = 0;
if (scache->loopstart != -1)
ch->pos = scache->loopstart<<PITCHSHIFT;
else if (!ch->looping)
else if (!(ch->flags & CF_FORCELOOP))
{
ch->sfx = NULL;
if (s->decoder.ended)
@ -257,7 +257,7 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
break;
}
}
else if (ch->looping && scache->length) /*(static)channels which are explicitly looping always loop from the start*/
else if ((ch->flags & CF_FORCELOOP) && scache->length) /*(static)channels which are explicitly looping always loop from the start*/
{
/*restart it*/
ch->pos = 0;

View File

@ -76,7 +76,7 @@ typedef struct {
} ovdecoderbuffer_t;
static sfxcache_t *OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf);
static sfxcache_t *OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf, int start, int length);
static sfxcache_t *OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf, ssamplepos_t start, int length);
static void OV_CancelDecoder(sfx_t *s);
static qboolean OV_StartDecode(unsigned char *start, unsigned long length, ovdecoderbuffer_t *buffer);
@ -137,7 +137,7 @@ static sfxcache_t *OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf)
return buf;
}
static sfxcache_t *OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf, int start, int length)
static sfxcache_t *OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf, ssamplepos_t start, int length)
{
extern int snd_speed;
extern cvar_t snd_linearresample_stream;
@ -183,6 +183,11 @@ static sfxcache_t *OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf, int
dec->decodedbytecount = 0;
dec->decodedbytestart = start;
}
else if (trim > dec->decodedbytecount)
{
dec->decodedbytecount = 0;
dec->decodedbytestart = start;
}
else
{
//FIXME: retain an extra half-second for dual+ sound devices running slightly out of sync

View File

@ -22,24 +22,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef __SOUND__
#define __SOUND__
// !!! if this is changed, it much be changed in asm_i386.h too !!!
#define MAXSOUNDCHANNELS 8 //on a per device basis
// !!! if this is changed, it much be changed in asm_i386.h too !!!
//pitch shifting can
#define ssamplepos_t qintptr_t
#define usamplepos_t quintptr_t
#define PITCHSHIFT 6 /*max audio file length = (1<<32>>PITCHSHIFT)/KHZ*/
struct sfx_s;
/*typedef struct
{
int left;
int right;
} portable_samplepair_t;
*/
typedef struct
{
int s[MAXSOUNDCHANNELS];
} portable_samplegroup_t;
typedef struct {
struct sfxcache_s *(*decodedata) (struct sfx_s *sfx, struct sfxcache_s *buf, int start, int length); //retrurn true when done.
struct sfxcache_s *(*decodedata) (struct sfx_s *sfx, struct sfxcache_s *buf, ssamplepos_t start, int length); //return true when done.
struct sfxcache_s *(*querydata) (struct sfx_s *sfx, struct sfxcache_s *buf); //reports length + format info without actually decoding anything.
void (*ended) (struct sfx_s *sfx); //sound stopped playing and is now silent (allow rewinding or something).
void (*purge) (struct sfx_s *sfx); //sound is being purged from memory. destroy everything.
@ -69,12 +66,12 @@ typedef struct sfx_s
// !!! if this is changed, it much be changed in asm_i386.h too !!!
typedef struct sfxcache_s
{
unsigned int length; //sample count
usamplepos_t length; //sample count
unsigned int loopstart; //-1 or sample index to begin looping at once the sample ends
unsigned int speed;
unsigned int width;
unsigned int numchannels;
unsigned int soundoffset; //byte index into the sound
usamplepos_t soundoffset; //byte index into the sound
qbyte *data; // variable sized
} sfxcache_t;
@ -92,17 +89,15 @@ typedef struct
unsigned char *buffer; // pointer to mixed pcm buffer (not directly used by mixer)
} dma_t;
#define PITCHSHIFT 6 /*max audio file length = (1<<32>>PITCHSHIFT)/KHZ*/
#define CF_ABSVOLUME 1 // ignores volume cvar.
#define CF_FORCELOOP 2 // forces looping. set on static sounds.
typedef struct
{
sfx_t *sfx; // sfx number
int vol[MAXSOUNDCHANNELS]; // volume, .8 fixed point.
int pos; // sample position in sfx, <0 means delay sound start (shifted up by 8)
ssamplepos_t pos; // sample position in sfx, <0 means delay sound start (shifted up by 8)
int rate; // 24.8 fixed point rate scaling
int flags; // cf_ flags
int looping; // where to loop, -1 = no looping
int entnum; // to allow overriding a specific sound
int entchannel; // to avoid overriding a specific sound too easily
vec3_t origin; // origin of sound effect
@ -128,24 +123,28 @@ void S_Startup (void);
void S_Shutdown (qboolean final);
float S_GetSoundTime(int entnum, int entchannel);
void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float timeofs, float pitchadj);
float S_UpdateSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float timeofs, float pitchadj);
void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation);
void S_StopSound (int entnum, int entchannel);
void S_StopAllSounds(qboolean clear);
void S_UpdateListener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up);
void S_GetListenerInfo(float *origin, float *forward, float *right, float *up);
void S_UpdateListener(int seat, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, qboolean underwater);
void S_GetListenerInfo(int seat, float *origin, float *forward, float *right, float *up);
void S_Update (void);
void S_ExtraUpdate (void);
void S_MixerThread(soundcardinfo_t *sc);
void S_Purge(qboolean retaintouched);
void S_LockMixer(void);
void S_UnlockMixer(void);
qboolean S_HaveOutput(void);
void S_Music_Clear(sfx_t *onlyifsample);
void S_Music_Seek(float time);
qboolean S_GetMusicInfo(int musicchannel, float *time, float *duration);
qboolean S_Music_Playing(int musicchannel);
float Media_CrossFade(int musicchanel, float vol); //queries the volume we're meant to be playing (checks for fade out). -1 for no more, otherwise returns vol.
char *Media_NextTrack(int musicchanel); //queries the track we're meant to be playing now.
float Media_CrossFade(int musicchanel, float vol, float time); //queries the volume we're meant to be playing (checks for fade out). -1 for no more, otherwise returns vol.
char *Media_NextTrack(int musicchanel, float *time); //queries the track we're meant to be playing now.
sfx_t *S_FindName (const char *name, qboolean create);
sfx_t *S_PrecacheSound (const char *sample);
@ -192,7 +191,6 @@ void SND_ResampleStream (void *in, int inrate, int inwidth, int inchannels, int
// restart entire sound subsystem (doesn't flush old sounds, so make sure that happens)
void S_DoRestart (void);
void S_SetUnderWater(qboolean underwater);
void S_Restart_f (void);
@ -235,10 +233,6 @@ void OpenAL_CvarInit(void);
extern int snd_speed;
extern vec3_t listener_origin;
extern vec3_t listener_forward;
extern vec3_t listener_right;
extern vec3_t listener_up;
extern vec_t sound_nominal_clip_dist;
extern cvar_t loadas8bit;
@ -284,7 +278,9 @@ extern sounddriver pAHI_InitCard;
struct soundcardinfo_s { //windows has one defined AFTER directsound
char name[256]; //a description of the card.
char guid[256]; //device name as detected (so input code can create sound devices without bugging out too much)
struct soundcardinfo_s *next;
int seat;
//speaker orientations for spacialisation.
float dist[MAXSOUNDCHANNELS];
@ -292,6 +288,7 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound
vec3_t speakerdir[MAXSOUNDCHANNELS];
//info on which sound effects are playing
//FIXME: use a linked list
channel_t channel[MAX_CHANNELS];
int total_chans;
@ -338,4 +335,6 @@ typedef struct
void (QDECL *Shutdown) (void *ctx); /*destroy everything*/
} snd_capture_driver_t;
void S_SetupDeviceSeat(char *driver, char *device, int seat);
#endif

View File

@ -388,11 +388,15 @@ dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs)
{
if (!strstr(COM_SkipPath(name), ".dll"))
{ //.dll implies that it is a system dll, or something that is otherwise windows-specific already.
char libname[MAX_OSPATH];
#ifdef _WIN64
lib = LoadLibraryU(va("%s_64", name));
Q_snprintfz(libname, sizeof(libname), "%s_64", name);
#elif defined(_WIN32)
lib = LoadLibraryU(va("%s_32", name));
Q_snprintfz(libname, sizeof(libname), "%s_32", name);
#else
#error wut? not win32?
#endif
lib = LoadLibraryU(libname);
}
if (!lib)
return NULL;
@ -2104,46 +2108,45 @@ void Sys_SendKeyEvents (void)
}
else if (avail)
{
if (avail > sizeof(text)-1-avail)
avail = sizeof(text)-1-avail;
if (avail > sizeof(text)-1-textpos)
avail = sizeof(text)-1-textpos;
if (ReadFile(input, text+textpos, avail, &avail, NULL))
{
textpos += avail;
if (textpos > sizeof(text)-1)
Sys_Error("No.");
while(1)
{
text[textpos] = 0;
nl = strchr(text, '\n');
if (nl)
{
*nl++ = 0;
if (qrenderer <= QR_NONE && !strncmp(text, "vid_recenter ", 13))
{
Cmd_TokenizeString(text, false, false);
sys_parentleft = strtoul(Cmd_Argv(1), NULL, 0);
sys_parenttop = strtoul(Cmd_Argv(2), NULL, 0);
sys_parentwidth = strtoul(Cmd_Argv(3), NULL, 0);
sys_parentheight = strtoul(Cmd_Argv(4), NULL, 0);
sys_parentwindow = (HWND)(intptr_t)strtoull(Cmd_Argv(5), NULL, 16);
}
#if !defined(CLIENTONLY) || defined(CSQC_DAT) || defined(MENU_DAT)
else if (QCExternalDebuggerCommand(text))
/*handled elsewhere*/;
#endif
else
{
Cbuf_AddText(text, RESTRICT_LOCAL);
Cbuf_AddText("\n", RESTRICT_LOCAL);
}
memmove(text, nl, textpos - (nl - text));
textpos -= (nl - text);
}
else
break;
}
}
}
while (textpos)
{
text[textpos] = 0;
nl = strchr(text, '\n');
if (nl)
{
*nl++ = 0;
if (qrenderer <= QR_NONE && !strncmp(text, "vid_recenter ", 13))
{
Cmd_TokenizeString(text, false, false);
sys_parentleft = strtoul(Cmd_Argv(1), NULL, 0);
sys_parenttop = strtoul(Cmd_Argv(2), NULL, 0);
sys_parentwidth = strtoul(Cmd_Argv(3), NULL, 0);
sys_parentheight = strtoul(Cmd_Argv(4), NULL, 0);
sys_parentwindow = (HWND)(intptr_t)strtoull(Cmd_Argv(5), NULL, 16);
}
#if !defined(CLIENTONLY) || defined(CSQC_DAT) || defined(MENU_DAT)
else if (QCExternalDebuggerCommand(text))
/*handled elsewhere*/;
#endif
else
{
Cbuf_AddText(text, RESTRICT_LOCAL);
Cbuf_AddText("\n", RESTRICT_LOCAL);
}
memmove(text, nl, textpos - (nl - text));
textpos -= (nl - text);
}
else
break;
}
}
if (isDedicated)
@ -2682,7 +2685,7 @@ void Update_PromptedDownloaded(void *ctx, int foo)
narrowen(cmdline, sizeof(cmdline), GetCommandLineW());
widen(wideexe, sizeof(wideexe), ctx);
widen(widearg, sizeof(widearg), va("\"%s\" %s", ctx, COM_Parse(cmdline)));
widen(widearg, sizeof(widearg), va("\"%s\" %s", (char*)ctx, COM_Parse(cmdline)));
CreateProcessW(wideexe, widearg, NULL, NULL, TRUE, 0, NULL, NULL, &startinfo, &childinfo);
Z_Free(ctx);
@ -2809,6 +2812,7 @@ void Update_Check(void)
dl = HTTP_CL_Get(va(UPDATE_URL_VERSION, updateroot), NULL, Update_Versioninfo_Available);
dl->file = FS_OpenTemp();
dl->user_ctx = updateroot;
dl->isquery = true;
#ifdef MULTITHREAD
DL_CreateThread(dl, NULL, NULL);
#endif

View File

@ -1303,16 +1303,16 @@ void V_CalcRefdef (playerview_t *pv)
{
float bob;
float viewheight;
r_refdef.playerview = pv;
memset(&r_refdef.globalfog, 0, sizeof(r_refdef.globalfog));
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
return;
#endif
CL_BlendFog(&r_refdef.globalfog, &cl.oldfog, realtime, &cl.fog);
r_refdef.globalfog.density /= 64; //FIXME
if (v_viewheight.value < -7)
bob=-7;
else if (v_viewheight.value > 4)
@ -1738,6 +1738,40 @@ void R_DrawNameTags(void)
w = &csqc_world;
#endif
}
else if ((r_showfields.ival & 3) == 3)
{
inframe_t *frame;
packet_entities_t *pak;
entity_state_t *state;
model_t *mod;
frame = &cl.inframes[cl.parsecount & UPDATE_MASK];
pak = &frame->packet_entities;
for (i=0 ; i<pak->num_entities ; i++)
{
state = &pak->entities[i];
mod = cl.model_precache[state->modelindex];
VectorInterpolate(mod->mins, 0.5, mod->maxs, org);
VectorAdd(org, state->origin, org);
if (Matrix4x4_CM_Project(org, screenspace, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y))
{
char *entstr;
int x, y;
entstr = va("%i", state->number);
if (entstr)
{
vec2_t scale = {8,8};
x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x;
y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y;
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, scale);
}
}
}
}
if (w && w->progs)
{
int best = 0;
@ -1841,7 +1875,7 @@ void R_DrawNameTags(void)
if (!cl.teamplay || !scr_autoid_team.ival)
isteam = false;
else if (cl.teamfortress && !cl.spectator) //teamfortress should go by their colours instead, because spies. primarily this is to allow enemy spies to appear through walls as well as your own team (note that the qc will also need tinfo stuff for tf, to avoid issues with just checking player names).
else if ((cl.teamfortress && !cl.spectator) || cls.protocol == CP_NETQUAKE) //teamfortress should go by their colours instead, because spies. primarily this is to allow enemy spies to appear through walls as well as your own team (note that the qc will also need tinfo stuff for tf, to avoid issues with just checking player names).
isteam = cl.players[i].rbottomcolor == ourcolour;
else
isteam = !strcmp(cl.players[i].team, ourteam);
@ -2055,15 +2089,17 @@ void V_RenderView (void)
V_RenderPlayerViews(r_refdef.playerview);
#ifdef PLUGINS
Plug_SBar (r_refdef.playerview);
Plug_SBar (r_refdef.playerview);
#else
if (Sbar_ShouldDraw())
{
Sbar_Draw (r_refdef.playerview);
Sbar_DrawScoreboard ();
}
if (Sbar_ShouldDraw())
{
SCR_TileClear (sb_lines);
Sbar_Draw (r_refdef.playerview);
Sbar_DrawScoreboard ();
}
else
SCR_TileClear (0);
#endif
SCR_TileClear ();
}
r_refdef.playerview = NULL;
}

View File

@ -683,7 +683,6 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
}
else if (!strcmp("fog", key)) //q1 extension. FIXME: should be made temporary.
{
void CL_Fog_f(void);
key[0] = 'f';
key[1] = 'o';
key[2] = 'g';
@ -691,6 +690,12 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in
Q_strncpyz(key+4, token, sizeof(key)-4);
Cbuf_AddText(key, RESTRICT_INSECURE);
}
else if (!strcmp("waterfog", key)) //q1 extension. FIXME: should be made temporary.
{
memcpy(key, "waterfog ", 9);
Q_strncpyz(key+9, token, sizeof(key)-9);
Cbuf_AddText(key, RESTRICT_INSECURE);
}
else if (!strncmp("cvar_", key, 5)) //override cvars so mappers don't end up hacking cvars and fucking over configs (at least in other engines).
{
cvar_t *var = Cvar_FindVar(key+5);

View File

@ -94,6 +94,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define AVAIL_DINPUT
#define AVAIL_DDRAW
#define AVAIL_DSOUND
// #define AVAIL_XAUDIO2
#define AVAIL_D3D
#endif
#define AVAIL_XZDEC

View File

@ -3090,7 +3090,7 @@ void Cmd_Condump_f(void)
{
vfsfile_t *f;
char *filename;
unsigned char c;
char line[8192];
if (!con_current)
{
@ -3120,17 +3120,12 @@ void Cmd_Condump_f(void)
{
console_t *curcon = &con_main;
conline_t *l;
int i;
conchar_t *t;
for (l = curcon->oldest; l; l = l->newer)
{
t = (conchar_t*)(l+1);
//FIXME: utf8?
for (i = 0; i < l->length; i++)
{
c = (qbyte)t[i]&0xff;
VFS_WRITE(f, &c, 1);
}
COM_DeFunString(t, t + l->length, line, sizeof(line), true);
VFS_WRITE(f, line, strlen(line));
VFS_WRITE(f, "\n", 1);
}
}

View File

@ -521,7 +521,7 @@ const float *Alias_ConvertBoneData(skeltype_t sourcetype, const float *sourcedat
//a->ia->ir
if (bonecount > destbonecount || bonecount > MAX_BONES)
Sys_Error("Alias_ConvertBoneData: too many bones %i>%i\n", bonecount, destbonecount);
Sys_Error("Alias_ConvertBoneData: too many bones "fPRIzu">"fPRIzu"\n", bonecount, destbonecount);
//r(->a)->ia(->ir)
if (desttype == SKEL_INVERSE_RELATIVE && sourcetype == SKEL_RELATIVE)
@ -3023,9 +3023,13 @@ static void *Q1_LoadSkins_GL (model_t *loadmodel, daliasskintype_t *pskintype, u
slash--;
memcpy(alttexpath, loadmodel->name, slash-loadmodel->name);
Q_strncpyz(alttexpath+(slash-loadmodel->name), ":models", sizeof(alttexpath)-(slash-loadmodel->name)); //fuhquake compat
slash++;
}
else
{
slash = loadmodel->name;
strcpy(alttexpath, "models"); //fuhquake compat
}
s = pq1inmodel->skinwidth*pq1inmodel->skinheight;
for (i = 0; i < pq1inmodel->numskins; i++)
@ -3128,21 +3132,21 @@ static void *Q1_LoadSkins_GL (model_t *loadmodel, daliasskintype_t *pskintype, u
frames[0].defaultshader = NULL;
Q_snprintfz(frames[0].shadername, sizeof(frames[0].shadername), "%s_%i.lmp", basename, i);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i.lmp", loadmodel->name, i);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i.lmp", slash, i);
frames[0].texnums.base = R_LoadReplacementTexture(skinname, alttexpath, texflags, frames[0].texels, outskin->skinwidth, outskin->skinheight, skintranstype);
if (r_fb_models.ival)
{
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_luma.lmp", loadmodel->name, i);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_luma.lmp", slash, i);
frames[0].texnums.fullbright = R_LoadReplacementTexture(skinname, alttexpath, texflags, frames[0].texels, outskin->skinwidth, outskin->skinheight, TF_TRANS8_FULLBRIGHT);
}
if (r_loadbumpmapping)
{
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_norm.lmp", loadmodel->name, i);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_norm.lmp", slash, i);
frames[0].texnums.bump = R_LoadReplacementTexture(skinname, alttexpath, texflags|IF_TRYBUMP, frames[0].texels, outskin->skinwidth, outskin->skinheight, TF_HEIGHT8PAL);
}
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_shirt.lmp", loadmodel->name, i);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_shirt.lmp", slash, i);
frames[0].texnums.upperoverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_pants.lmp", loadmodel->name, i);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_pants.lmp", slash, i);
frames[0].texnums.loweroverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID);
switch(skintranstype)
@ -3226,21 +3230,21 @@ static void *Q1_LoadSkins_GL (model_t *loadmodel, daliasskintype_t *pskintype, u
//other engines apparently don't flood fill. because flood filling is horrible, we won't either.
//Mod_FloodFillSkin(frames[t].texels, outskin->skinwidth, outskin->skinheight);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i.lmp", loadmodel->name, i, t);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i.lmp", slash, i, t);
frames[t].texnums.base = R_LoadReplacementTexture(skinname, alttexpath, texflags, frames[t].texels, outskin->skinwidth, outskin->skinheight, skintranstype);
if (r_fb_models.ival)
{
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i_luma.lmp", loadmodel->name, i, t);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i_luma.lmp", slash, i, t);
frames[t].texnums.fullbright = R_LoadReplacementTexture(skinname, alttexpath, texflags, frames[t].texels, outskin->skinwidth, outskin->skinheight, TF_TRANS8_FULLBRIGHT);
}
if (r_loadbumpmapping)
{
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i_norm.lmp", loadmodel->name, i, t);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i_norm.lmp", slash, i, t);
frames[t].texnums.bump = R_LoadReplacementTexture(skinname, alttexpath, texflags|IF_TRYBUMP, frames[t].texels, outskin->skinwidth, outskin->skinheight, TF_HEIGHT8PAL);
}
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i_shirt.lmp", loadmodel->name, i, t);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i_shirt.lmp", slash, i, t);
frames[t].texnums.upperoverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i_pants.lmp", loadmodel->name, i, t);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i_pants.lmp", slash, i, t);
frames[t].texnums.loweroverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID);
Q_snprintfz(frames[t].shadername, sizeof(frames[t].shadername), "%s_%i_%i.lmp", basename, i, t);
@ -6515,7 +6519,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
}
if (h->filesize != fsize)
{
Con_Printf("%s: size (%u != %u)\n", mod->name, h->filesize, fsize);
Con_Printf("%s: size (%u != "fPRIzu")\n", mod->name, h->filesize, fsize);
return NULL;
}

View File

@ -5058,7 +5058,7 @@ void COM_WorkerPartialSync(void *priorityctx, int *address, int value)
Sys_UnlockConditional(com_workercondition[thread]);
}
if (!found)
Con_DPrintf("Might be in for a long wait for %s\n", priorityctx);
Con_DPrintf("Might be in for a long wait for %s\n", (char*)priorityctx);
}
Sys_LockConditional(com_workercondition[0]);

View File

@ -30,6 +30,48 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#endif
#if __STDC_VERSION__ >= 199901L
//C99 has a stdint header which hopefully contains an intptr_t
//its optional... but if its not in there then its unlikely you'll actually be able to get the engine to a stage where it *can* load anything
#include <stdint.h>
#define qintptr_t intptr_t
#define quintptr_t uintptr_t
#else
#if defined(_WIN64)
#define qintptr_t __int64
#define FTE_WORDSIZE 64
#define quintptr_t unsigned qintptr_t
#elif defined(_WIN32)
#ifndef _MSC_VER
#define __w64
#endif
typedef __int32 __w64 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions
typedef unsigned __int32 __w64 quintptr_t;
// #define qintptr_t __int32
// #define quintptr_t unsigned qintptr_t
#define FTE_WORDSIZE 32
#else
#if __WORDSIZE == 64
#define qintptr_t long long
#define FTE_WORDSIZE 64
#else
#define qintptr_t long
#define FTE_WORDSIZE 32
#endif
#define quintptr_t unsigned qintptr_t
#endif
#endif
#ifndef FTE_WORDSIZE
#ifdef __WORDSIZE
#define FTE_WORDSIZE __WORDSIZE
#else
#define FTE_WORDSIZE 32
#endif
#endif
typedef unsigned char qbyte;
// KJB Undefined true and false defined in SciTech's DEBUG.H header

View File

@ -2563,7 +2563,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
FS_ChangeGame(man, cfg_reload_on_gamedir.ival, false);
}
#define QCFG "set allow_download_refpackages 0\nmap_autoopenportals 1\n"
#define QCFG "set allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n"
/*stuff that makes dp-only mods work a bit better*/
#define DPCOMPAT QCFG "set _cl_playermodel \"\"\n set dpcompat_set 1\nset dpcompat_corruptglobals 1\nset vid_pixelheight 1\n"
/*nexuiz/xonotic has a few quirks/annoyances...*/
@ -3352,7 +3352,7 @@ qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char *
narrowen(basepath, basepathsize, resultpath);
if (savedname)
{
if (MessageBoxU(mainwindow, va("Would you like to save the location of %s as:\n%s", poshname, resultpath), "Save Instaltion path", MB_YESNO|MB_DEFBUTTON2) == IDYES)
if (MessageBoxU(mainwindow, va("Would you like to save the location of %s as:\n%s", poshname, basepath), "Save Instaltion path", MB_YESNO|MB_DEFBUTTON2) == IDYES)
MyRegSetValue(HKEY_CURRENT_USER, "SOFTWARE\\" FULLENGINENAME "\\GamePaths", savedname, REG_SZ, basepath, strlen(basepath));
}
return true;

View File

@ -4274,6 +4274,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
Q_snprintfz (name, sizeof(name), "*%i:%s", i, wmod->name);
mod = Mod_FindName (name);
*mod = *wmod;
mod->submodelof = wmod;
Q_strncpyz(mod->name, name, sizeof(mod->name));
memset(&mod->memgroup, 0, sizeof(mod->memgroup));

View File

@ -145,10 +145,11 @@ typedef struct
int isnqprotocol;
qboolean nqreliable_allowed; //says the peer has acked the last reliable (or timed out and needs resending).
float nqreliable_resendtime;//force nqreliable_allowed, thereby forcing a resend of anything n
qboolean nqunreliableonly; //prohibits new reliables, but allows resends.
qbyte nqunreliableonly; //nq can't cope with certain reliables some times. if 2, we have a reliable that result in a block (that should be sent). if 1, we are blocking. if 0, we can send reliables freely.
#endif
struct netprim_s netprim;
int fragmentsize;
int dupe;
float last_received; // for timeouts

View File

@ -582,8 +582,10 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (chan->nqreliable_allowed)
{
//consume the new reliable when we can.
if (!chan->reliable_length && chan->message.cursize && !chan->nqunreliableonly)
if (!chan->reliable_length && chan->message.cursize && chan->nqunreliableonly != 1)
{
if (chan->nqunreliableonly == 2)
chan->nqunreliableonly = 1;
memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
chan->reliable_length = chan->message.cursize;
chan->reliable_start = 0;
@ -741,7 +743,11 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
int hsz = 10 + ((chan->sock == NS_CLIENT)?2:0); /*header size, if fragmentation is in use*/
if ((!chan->fragmentsize) || send.cursize-hsz < ((chan->fragmentsize - hsz)&~7))
NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
{
for (i = -1; i < chan->dupe; i++)
NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
send.cursize += send.cursize * chan->dupe;
}
else
{
int offset = chan->fragmentsize - hsz, no;

View File

@ -226,7 +226,7 @@ static void SSPI_Decode(sslfile_t *f)
switch(ss)
{
case SEC_E_INVALID_HANDLE: SSPI_Error(f, "DecryptMessage failed: SEC_E_INVALID_HANDLE\n"); break;
default: SSPI_Error(f, va("DecryptMessage failed: %0#x\n", ss)); break;
default: SSPI_Error(f, va("DecryptMessage failed: %0#lx\n", ss)); break;
}
return;
}
@ -392,37 +392,37 @@ static DWORD VerifyKnownCertificates(DWORD status, wchar_t *domain, qbyte *data,
static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServerName, DWORD dwCertFlags)
{
HTTPSPolicyCallbackData polHttps;
CERT_CHAIN_POLICY_PARA PolicyPara;
CERT_CHAIN_POLICY_STATUS PolicyStatus;
CERT_CHAIN_PARA ChainPara;
PCCERT_CHAIN_CONTEXT pChainContext;
DWORD Status;
LPSTR rgszUsages[] =
HTTPSPolicyCallbackData polHttps;
CERT_CHAIN_POLICY_PARA PolicyPara;
CERT_CHAIN_POLICY_STATUS PolicyStatus;
CERT_CHAIN_PARA ChainPara;
PCCERT_CHAIN_CONTEXT pChainContext;
DWORD Status;
LPSTR rgszUsages[] =
{
szOID_PKIX_KP_SERVER_AUTH,
szOID_SERVER_GATED_CRYPTO,
szOID_SGC_NETSCAPE
};
DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
if(pServerCert == NULL)
if(pServerCert == NULL)
return SEC_E_WRONG_PRINCIPAL;
if(!*pwszServerName)
if(!*pwszServerName)
return SEC_E_WRONG_PRINCIPAL;
// Build certificate chain.
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
// Build certificate chain.
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
if (!crypt.pCertGetCertificateChain(NULL, pServerCert, NULL, pServerCert->hCertStore, &ChainPara, 0, NULL, &pChainContext))
{
Status = GetLastError();
Sys_Printf("Error 0x%x returned by CertGetCertificateChain!\n", (unsigned int)Status);
}
if (!crypt.pCertGetCertificateChain(NULL, pServerCert, NULL, pServerCert->hCertStore, &ChainPara, 0, NULL, &pChainContext))
{
Status = GetLastError();
Sys_Printf("Error %#lx returned by CertGetCertificateChain!\n", Status);
}
else
{
// Validate certificate chain.
@ -442,7 +442,7 @@ static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServe
if (!crypt.pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus))
{
Status = GetLastError();
Sys_Printf("Error 0x%x returned by CertVerifyCertificateChainPolicy!\n", (unsigned int)Status);
Sys_Printf("Error %#lx returned by CertVerifyCertificateChainPolicy!\n", Status);
}
else
{
@ -700,7 +700,7 @@ static void SSPI_Handshake (sslfile_t *f)
case SEC_E_INVALID_HANDLE: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_INVALID_HANDLE\n"); break;
case SEC_E_ILLEGAL_MESSAGE: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE\n"); break;
case SEC_E_INVALID_TOKEN: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_INVALID_TOKEN\n"); break;
default: SSPI_Error(f, va("InitializeSecurityContext failed: %#x\n", ss)); break;
default: SSPI_Error(f, va("InitializeSecurityContext failed: %#lx\n", ss)); break;
}
return;
}

View File

@ -3366,12 +3366,12 @@ handshakeerror:
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+7]<< 0ull;
if (ullpaylen < 0x10000)
{
Con_Printf ("%s: payload size (%llu) encoded badly\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
Con_Printf ("%s: payload size ("fPRIllu") encoded badly\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
goto closesvstream;
}
if (ullpaylen > 0x10000)
{
Con_Printf ("%s: payload size (%llu) is abusive\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), st->inbuffer, ullpaylen);
Con_Printf ("%s: payload size ("fPRIllu") is abusive\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
goto closesvstream;
}
paylen = ullpaylen;

View File

@ -95,8 +95,7 @@ void P_Shutdown(void);
void P_LoadedModel(struct model_s *mod); /*checks a model's various effects*/
void P_DefaultTrail (unsigned int entityeffects, unsigned int modelflags, int *trailid, int *trailpalidx);
void P_EmitEffect (vec3_t pos, int type, trailstate_t **tsk);//this is just a wrapper
#define P_FindParticleType pe->FindParticleType
int P_FindParticleType(const char *efname);
#define P_RunParticleEffectTypeString pe->RunParticleEffectTypeString
#define P_ParticleTrail pe->ParticleTrail

View File

@ -688,7 +688,7 @@ static qintptr_t VARGS Plug_Cvar_GetString(void *offset, quintptr_t mask, const
#ifdef CLIENTONLY
Q_strncpyz(ret, "", retsize);
#else
Q_strncpyz(ret, sv.name, retsize);
Q_strncpyz(ret, svs.name, retsize);
#endif
}
else
@ -1635,9 +1635,13 @@ void Plug_SBar(playerview_t *pv)
plugin_t *oc=currentplug;
int ret;
int cleared = false;
if (!Sbar_ShouldDraw())
{
SCR_TileClear (0);
return;
}
ret = 0;
if (!plug_sbar.ival)
@ -1650,6 +1654,11 @@ void Plug_SBar(playerview_t *pv)
{
//if you don't use splitscreen, use a full videosize rect.
R2D_ImageColours(1, 1, 1, 1); // ensure menu colors are reset
if (!cleared)
{
cleared = true;
SCR_TileClear (0);
}
ret |= VM_Call(currentplug->vm, currentplug->sbarlevel[0], pv-cl.playerview, (int)r_refdef.vrect.x, (int)r_refdef.vrect.y, (int)r_refdef.vrect.width, (int)r_refdef.vrect.height, sb_showscores+sb_showteamscores*2);
break;
}
@ -1657,6 +1666,8 @@ void Plug_SBar(playerview_t *pv)
}
if (!(ret & 1))
{
if (!cleared)
SCR_TileClear (sb_lines);
Sbar_Draw(pv);
}

View File

@ -239,6 +239,7 @@ qboolean QCExternalDebuggerCommand(char *text)
Cbuf_AddText("restart\n", RESTRICT_LOCAL);
#endif
// Host_EndGame("Reloading QC");
debuggerresume = DEBUG_TRACE_ABORT;
}
else if (!strncmp(text, "qcbreakpoint ", 13))
{
@ -280,7 +281,7 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
return DEBUG_TRACE_ABORT;
if (!*filename || !line || !*line) //don't try editing an empty line, it won't work
{
Con_Printf("Unable to debug, pelase disable optimisations\n");
Con_Printf("Unable to debug, please disable optimisations\n");
return DEBUG_TRACE_OFF;
}
Sys_SendKeyEvents();
@ -321,6 +322,7 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
VID_SwapBuffers();
}
}
Con_Footerf(NULL, false, "");
*line = debuggerresumeline;
debuggerinstance = NULL;
debuggerfile = NULL;
@ -1450,11 +1452,13 @@ void QCBUILTIN PF_memgetval (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
if (ofs != (float)(int)ofs)
PR_BIError(prinst, "PF_memgetval: non-integer offset\n");
dst += ofs;
if (dst & 3 || dst < 0 || dst+size >= prinst->stringtablesize)
if (dst < 0 || dst+size >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_memgetval: invalid dest\n");
return;
}
if (dst & 3)
PF_Warningf(prinst, "PF_memgetval: misaligned pointer (%#x)\n", dst);
G_INT(OFS_RETURN) = *(int*)(prinst->stringtable + dst);
}
@ -1468,11 +1472,13 @@ void QCBUILTIN PF_memsetval (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
if (ofs != (float)(int)ofs)
PR_BIError(prinst, "PF_memsetval: non-integer offset\n");
dst += ofs;
if (dst & 3 || dst < 0 || dst+size >= prinst->stringtablesize)
if (dst < 0 || dst+size >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_memsetval: invalid dest\n");
return;
}
if (dst & 3)
PF_Warningf(prinst, "PF_memgetval: misaligned pointer (%#x)\n", dst);
*(int*)(prinst->stringtable + dst) = val;
}
@ -1488,6 +1494,12 @@ void QCBUILTIN PF_memptradd (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
G_INT(OFS_RETURN) = dst + ofs;
}
void QCBUILTIN PF_memstrsize(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = strlen(PR_GetStringOfs(prinst, OFS_PARM0));
}
//memory stuff
////////////////////////////////////////////////////
//hash table stuff
@ -1811,10 +1823,7 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
{
vfsfile_t *f = FS_OpenVFS(pf_fopen_files[i].name, "rb", FS_GAME);
if (!f && fallbackread)
{
Q_strncpyz(pf_fopen_files[i].name, fallbackread, sizeof(pf_fopen_files[i].name));
f = FS_OpenVFS(pf_fopen_files[i].name, "rb", FS_GAME);
}
f = FS_OpenVFS(fallbackread, "rb", FS_GAME);
if (f)
{
pf_fopen_files[i].bufferlen = pf_fopen_files[i].len = VFS_GETLEN(f);
@ -2753,6 +2762,27 @@ void QCBUILTIN PF_strpad (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
RETURN_TSTRING(destbuf);
}
void QCBUILTIN PF_strtrim (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
const char *end;
char *news;
//figure out the new start
while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r')
str++;
//figure out the new end.
end = str + strlen(str);
while(end > str && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\n' || end[-1] == '\r'))
end--;
//copy that substring into a tempstring.
((int *)pr_globals)[OFS_RETURN] = prinst->AllocTempString(prinst, &news, end - str + 1);
memcpy(news, str, end-str);
news[end-str] = 0;
}
//part of PF_strconv
static int chrconv_number(int i, int base, int conv)
{
@ -2987,6 +3017,15 @@ void QCBUILTIN PF_ftos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
RETURN_TSTRING(pr_string_temp);
}
void QCBUILTIN PF_ftoi (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_INT(OFS_RETURN) = G_FLOAT(OFS_PARM0);
}
void QCBUILTIN PF_itof (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = G_INT(OFS_PARM0);
}
//tstring(integer input) itos
void QCBUILTIN PF_itos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -4863,7 +4902,7 @@ void QCBUILTIN PF_eprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
{
int max = 1024*1024;
int size = 0;
char *buffer = BZ_Malloc(size);
char *buffer = BZ_Malloc(max);
char *buf;
buf = prinst->saveent(prinst, buffer, &size, max, (struct edict_s*)G_WEDICT(prinst, OFS_PARM0));
Con_Printf("Entity %i:\n%s\n", G_EDICTNUM(prinst, OFS_PARM0), buf);
@ -5322,7 +5361,7 @@ void QCBUILTIN PF_findentityfield (pubprogfuncs_t *prinst, struct globalvars_s *
G_FLOAT(OFS_RETURN) = 0;
for (fidx = 0; fidx < count; fidx++)
{
if (!strcmp(fdef->name, fieldname))
if (!strcmp(fdef[fidx].name, fieldname))
{
G_FLOAT(OFS_RETURN) = fidx;
break;

View File

@ -185,6 +185,8 @@ void QCBUILTIN PF_itos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_stoi (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_stoh (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_htos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_ftoi (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_itof (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void PR_fclose_progs (pubprogfuncs_t *prinst);
char *PF_VarString (pubprogfuncs_t *prinst, int first, struct globalvars_s *pr_globals);
void PR_ProgsAdded(pubprogfuncs_t *prinst, int newprogs, const char *modulename);
@ -322,6 +324,7 @@ void QCBUILTIN PF_infoget (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
void QCBUILTIN PF_strncmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strncasecmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strpad (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strtrim (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -445,6 +448,7 @@ void QCBUILTIN PF_memfill8 (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
void QCBUILTIN PF_memgetval (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memsetval (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memptradd (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memstrsize(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_soundlength (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_calltimeofday (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

View File

@ -811,6 +811,7 @@ enum clcq2_ops_e
#define DPSND_LOOPING (1<<2) // a long, supposedly
#define DPSND_LARGEENTITY (1<<3)
#define DPSND_LARGESOUND (1<<4)
#define FTESND_TIMEOFS (1<<6) //signed short, in milliseconds.
#define FTESND_PITCHADJ (1<<7) //a byte (speed percent (0=100%))
#define DEFAULT_SOUND_PACKET_VOLUME 255

View File

@ -7,46 +7,6 @@
#define EXPORT_FN
#endif
#if __STDC_VERSION__ >= 199901L
//C99 has a stdint header which hopefully contains an intptr_t
//its optional... but if its not in there then its unlikely you'll actually be able to get the engine to a stage where it *can* load anything
#include <stdint.h>
#define qintptr_t intptr_t
#define quintptr_t uintptr_t
#else
#if defined(_WIN64)
#define qintptr_t __int64
#define FTE_WORDSIZE 64
#define quintptr_t unsigned qintptr_t
#elif defined(_WIN32)
#ifndef _MSC_VER
#define __w64
#endif
typedef __int32 __w64 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions
typedef unsigned __int32 __w64 quintptr_t;
// #define qintptr_t __int32
// #define quintptr_t unsigned qintptr_t
#define FTE_WORDSIZE 32
#else
#if __WORDSIZE == 64
#define qintptr_t long long
#define FTE_WORDSIZE 64
#else
#define qintptr_t long
#define FTE_WORDSIZE 32
#endif
#define quintptr_t unsigned qintptr_t
#endif
#endif
#ifndef FTE_WORDSIZE
#ifdef __WORDSIZE
#define FTE_WORDSIZE __WORDSIZE
#else
#define FTE_WORDSIZE 32
#endif
#endif
typedef qintptr_t (EXPORT_FN *sys_calldll_t) (qintptr_t arg, ...);
typedef int (*sys_callqvm_t) (void *offset, quintptr_t mask, int fn, const int *arg);

View File

@ -171,7 +171,7 @@ struct world_s
{
void (*Event_Touch)(struct world_s *w, wedict_t *s, wedict_t *o);
void (*Event_Think)(struct world_s *w, wedict_t *s);
void (*Event_Sound) (float *origin, wedict_t *entity, int channel, const char *sample, int volume, float attenuation, int pitchadj);
void (*Event_Sound) (float *origin, wedict_t *entity, int channel, const char *sample, int volume, float attenuation, int pitchadj, float timeoffset);
qboolean (*Event_ContentsTransition) (struct world_s *w, wedict_t *ent, int oldwatertype, int newwatertype);
model_t *(*Get_CModel)(struct world_s *w, int modelindex);
void (*Get_FrameState)(struct world_s *w, wedict_t *s, framestate_t *fstate);

View File

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

View File

@ -43,7 +43,11 @@ Things to improve:
extern LPDIRECT3DDEVICE9 pD3DDev9;
//#define d3dcheck(foo) foo
#ifdef _DEBUG
#define d3dcheck(foo) do{HRESULT err = foo; if (FAILED(err)) Sys_Error("D3D reported error on backend line %i - error 0x%x\n", __LINE__, (unsigned int)err);} while(0)
#else
#define d3dcheck(foo) foo
#endif
#define MAX_TMUS 16
@ -506,6 +510,9 @@ void D3D9BE_Reset(qboolean before)
D3DVERTEXELEMENT9 decl[13], declend=D3DDECL_END();
int elements;
if (shaderstate.dynidx_buff)
return;
for (i = 0; i < D3D_VDEC_MAX; i++)
{
elements = 0;
@ -595,7 +602,7 @@ void D3D9BE_Reset(qboolean before)
}
IDirect3DDevice9_CreateVertexBuffer(pD3DDev9, shaderstate.dynxyz_size, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &shaderstate.dynxyz_buff, NULL);
for (tmu = 0; tmu < D3D_VDEC_ST0; tmu++)
for (tmu = 0; tmu < MAX_TC_TMUS; tmu++)
IDirect3DDevice9_CreateVertexBuffer(pD3DDev9, shaderstate.dynst_size, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &shaderstate.dynst_buff[tmu], NULL);
IDirect3DDevice9_CreateVertexBuffer(pD3DDev9, shaderstate.dynnorm_size, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &shaderstate.dynnorm_buff, NULL);
IDirect3DDevice9_CreateVertexBuffer(pD3DDev9, shaderstate.dyncol_size, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &shaderstate.dyncol_buff, NULL);
@ -610,6 +617,9 @@ void D3D9BE_Reset(qboolean before)
/*force all state to change, thus setting a known state*/
shaderstate.shaderbits = ~0;
BE_ApplyShaderBits(0);
Surf_BuildLightmaps();
}
}
@ -1676,41 +1686,15 @@ static qboolean BE_DrawMeshChain_SetupPass(shaderpass_t *pass, unsigned int vert
return true;
}
static void BE_SubmitMeshChain(int idxfirst)
static void BE_SubmitMeshChain(unsigned int vertbase, unsigned int firstvert, unsigned int vertcount, unsigned int idxfirst, int unsigned idxcount)
{
int startv, starti, endv, endi;
int m;
mesh_t *mesh;
if (shaderstate.flags & BEF_LINES)
IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_LINELIST, vertbase, firstvert, vertcount, idxfirst, idxcount/2);
else
IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, vertbase, firstvert, vertcount, idxfirst, idxcount/3);
RQuantAdd(RQUANT_DRAWS, 1);
// if (shaderstate.batchvbo)
// IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, 0, 0, shaderstate.batchvbo->vertcount, idxfirst, shaderstate.batchvbo->indexcount/3);
for (m = 0, mesh = shaderstate.meshlist[0]; m < shaderstate.nummeshes; )
{
startv = mesh->vbofirstvert;
starti = mesh->vbofirstelement;
endv = startv+mesh->numvertexes;
endi = starti+mesh->numindexes;
//find consecutive surfaces
for (++m; m < shaderstate.nummeshes; m++)
{
mesh = shaderstate.meshlist[m];
if (endi == mesh->vbofirstelement)
{
endv = mesh->vbofirstvert+mesh->numvertexes;
endi = mesh->vbofirstelement+mesh->numindexes;
}
else
{
break;
}
}
IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, 0, startv, endv - startv, idxfirst + starti, (endi-starti)/3);
RQuantAdd(RQUANT_DRAWS, 1);
}
RQuantAdd(RQUANT_PRIMITIVEINDICIES, idxcount);
}
static void BE_ApplyUniforms(program_t *prog, int permu)
@ -1824,9 +1808,9 @@ static void BE_ApplyUniforms(program_t *prog, int permu)
}
}
static void BE_RenderMeshProgram(shader_t *s, unsigned int vertcount, unsigned int idxfirst, unsigned int idxcount)
static void BE_RenderMeshProgram(shader_t *s, unsigned int vertbase, unsigned int vertfirst, unsigned int vertcount, unsigned int idxfirst, unsigned int idxcount)
{
int vdec = D3D_VDEC_ST0|D3D_VDEC_NORM;
int vdec = D3D_VDEC_ST0|D3D_VDEC_ST1|D3D_VDEC_NORM;
int passno;
int perm = 0;
@ -2014,7 +1998,7 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertcount, unsigned i
}
// IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9,
BE_SubmitMeshChain(idxfirst);
BE_SubmitMeshChain(vertbase, vertfirst, vertcount, idxfirst, idxcount);
IDirect3DDevice9_SetVertexShader(pD3DDev9, NULL);
IDirect3DDevice9_SetPixelShader(pD3DDev9, NULL);
@ -2049,7 +2033,7 @@ void D3D9BE_Cull(unsigned int cullflags)
static void BE_DrawMeshChain_Internal(void)
{
unsigned int vertcount, idxcount, idxfirst;
unsigned int vertbase, vertfirst, vertcount, idxcount, idxfirst;
mesh_t *m;
void *map;
int i;
@ -2075,13 +2059,21 @@ static void BE_DrawMeshChain_Internal(void)
// IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&shaderstate.depthfactor);
// }
//if anything is dynamic ALL must be dynamic
//might want to flag this for multi-mesh batches on pre-t&l cards too, so that there's no gaps.
if (shaderstate.curshader->numdeforms)
shaderstate.batchvbo = NULL;
if (shaderstate.batchvbo)
{
vertfirst = 0;
vertcount = shaderstate.batchvbo->vertcount;
idxfirst = 0;
idxcount = shaderstate.batchvbo->indexcount;
}
else
{
vertfirst = 0;
for (mno = 0, vertcount = 0, idxcount = 0; mno < shaderstate.nummeshes; mno++)
{
m = shaderstate.meshlist[mno];
@ -2091,12 +2083,14 @@ static void BE_DrawMeshChain_Internal(void)
}
/*vertex buffers are common to all passes*/
if (shaderstate.batchvbo && !shaderstate.curshader->numdeforms)
if (shaderstate.batchvbo)
{
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_VERT, shaderstate.batchvbo->coord.d3d.buff, shaderstate.batchvbo->coord.d3d.offs, sizeof(vbovdata_t)));
vertfirst = 0;
}
else
{
vertfirst = 0;
allocvertexbuffer(shaderstate.dynxyz_buff, shaderstate.dynxyz_size, &shaderstate.dynxyz_offs, &map, vertcount*sizeof(vecV_t));
for (mno = 0, vertcount = 0; mno < shaderstate.nummeshes; mno++)
{
@ -2113,11 +2107,44 @@ static void BE_DrawMeshChain_Internal(void)
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_VERT, shaderstate.dynxyz_buff, shaderstate.dynxyz_offs - vertcount*sizeof(vecV_t), sizeof(vecV_t)));
}
/*so are index buffers*/
/*index buffers are also common (note that we may still need to stream these when dealing with bsp geometry, to cope with gaps. this is faster than using multiple draw calls.)*/
if (shaderstate.batchvbo)
{
d3dcheck(IDirect3DDevice9_SetIndices(pD3DDev9, shaderstate.batchvbo->indicies.d3d.buff));
idxfirst = 0;
if (shaderstate.nummeshes != 1)
{ //in this case, the vertex data is static, but the index data can have gaps.
//we're streaming index buffer data only so that we can avoid repeated draw calls. if this stuff was properly built in the first place we wouldn't need to do this. :s
idxcount = 0;
for (mno = 0; mno < shaderstate.nummeshes; mno++)
{
m = shaderstate.meshlist[mno];
idxcount += m->numindexes;
}
idxfirst = allocindexbuffer(&map, idxcount);
for (mno = 0; mno < shaderstate.nummeshes; mno++)
{
m = shaderstate.meshlist[mno];
for (i = 0; i < m->numindexes; i++)
((index_t*)map)[i] = m->vbofirstvert + m->indexes[i];
map = (char*)map + m->numindexes*sizeof(index_t);
}
d3dcheck(IDirect3DIndexBuffer9_Unlock(shaderstate.dynidx_buff));
d3dcheck(IDirect3DDevice9_SetIndices(pD3DDev9, shaderstate.dynidx_buff));
//we could constrain vertfirst+vertcount, but I suspect those only matter on pre t&l cards, of which there are very few.
vertbase = 0;
}
else
{
m = shaderstate.meshlist[0];
vertbase = 0;//-m->vbofirstvert;
idxfirst = m->vbofirstelement;
idxcount = m->numindexes;
vertfirst = m->vbofirstvert;
vertcount = m->numvertexes;
d3dcheck(IDirect3DDevice9_SetIndices(pD3DDev9, shaderstate.batchvbo->indicies.d3d.buff));
}
}
else
{
@ -2132,13 +2159,43 @@ static void BE_DrawMeshChain_Internal(void)
}
d3dcheck(IDirect3DIndexBuffer9_Unlock(shaderstate.dynidx_buff));
d3dcheck(IDirect3DDevice9_SetIndices(pD3DDev9, shaderstate.dynidx_buff));
vertbase = 0;
}
switch (shaderstate.mode)
{
case BEM_LIGHT:
if (shaderstate.shader_rtlight->prog)
BE_RenderMeshProgram(shaderstate.shader_rtlight, vertcount, idxfirst, idxcount);
BE_RenderMeshProgram(shaderstate.shader_rtlight, vertbase, vertfirst, vertcount, idxfirst, idxcount);
break;
case BEM_DEPTHDARK:
shaderstate.lastpasscount = 0;
i = 0;
if (i != shaderstate.curvertdecl)
{
shaderstate.curvertdecl = i;
d3dcheck(IDirect3DDevice9_SetVertexDeclaration(pD3DDev9, vertexdecls[shaderstate.curvertdecl]));
}
/*deactivate any extras*/
for (passno = 1; passno < shaderstate.lastpasscount; )
{
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+passno, NULL, 0, 0));
BindTexture(passno, NULL);
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_COLOROP, D3DTOP_DISABLE));
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAOP, D3DTOP_DISABLE));
passno++;
}
BindTexture(passno, NULL);
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1));
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, 0, D3DTSS_COLORARG1, D3DTA_CONSTANT));
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, 0, D3DTSS_CONSTANT, D3DCOLOR_RGBA(0,0,0,255)));
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE));
shaderstate.lastpasscount = 1;
BE_ApplyShaderBits(SBITS_MISC_DEPTHWRITE);
BE_SubmitMeshChain(vertbase, vertfirst, vertcount, idxfirst, idxcount);
break;
case BEM_STENCIL:
break;
case BEM_DEPTHONLY:
shaderstate.lastpasscount = 0;
@ -2159,14 +2216,15 @@ static void BE_DrawMeshChain_Internal(void)
passno++;
}
shaderstate.lastpasscount = 0;
BE_SubmitMeshChain(idxfirst);
BE_ApplyShaderBits(SBITS_MISC_DEPTHWRITE);
BE_SubmitMeshChain(vertbase, vertfirst, vertcount, idxfirst, idxcount);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_ALPHA);
break;
default:
case BEM_STANDARD:
if (shaderstate.curshader->prog)
{
BE_RenderMeshProgram(shaderstate.curshader, vertcount, idxfirst, idxcount);
BE_RenderMeshProgram(shaderstate.curshader, vertbase, vertfirst, vertcount, idxfirst, idxcount);
}
else
{
@ -2180,7 +2238,7 @@ static void BE_DrawMeshChain_Internal(void)
if (shaderstate.bench.clamp && shaderstate.bench.clamp < shaderstate.bench.draws)
continue;
#endif
BE_SubmitMeshChain(idxfirst);
BE_SubmitMeshChain(vertbase, vertfirst, vertcount, idxfirst, idxcount);
// d3dcheck(IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, 0, 0, vertcount, idxfirst, idxcount/3));
}
}
@ -2570,8 +2628,8 @@ static void BE_UploadLightmaps(qboolean force)
glRect_t *theRect = &lm->rectchange;
int r;
if (!lm->lightmap_texture)
lm->lightmap_texture = Image_CreateTexture("", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP);
if (!TEXLOADED(lm->lightmap_texture))
lm->lightmap_texture = Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP);
tex = lm->lightmap_texture->ptr;
if (!tex)
{
@ -2579,6 +2637,7 @@ static void BE_UploadLightmaps(qboolean force)
if (!tex)
continue;
lm->lightmap_texture->ptr = tex;
lm->lightmap_texture->status = TEX_LOADED;
}
lm->modified = 0;
@ -2774,7 +2833,12 @@ void D3D9BE_DrawMesh_List(shader_t *shader, int nummeshes, mesh_t **meshlist, vb
{
shaderstate.batchvbo = vbo;
shaderstate.curshader = shader;
shaderstate.curtexnums = texnums;
if (texnums)
shaderstate.curtexnums = texnums;
else if (shader->numdefaulttextures)
shaderstate.curtexnums = shader->defaulttextures + ((int)(shader->defaulttextures_fps * shaderstate.curtime) % shader->numdefaulttextures);
else
shaderstate.curtexnums = shader->defaulttextures;
shaderstate.curlightmap = r_nulltex;
shaderstate.curbatch = &shaderstate.dummybatch;
shaderstate.meshlist = meshlist;
@ -3148,6 +3212,17 @@ void D3D9BE_BaseEntTextures(void)
void D3D9BE_RenderShadowBuffer(unsigned int numverts, IDirect3DVertexBuffer9 *vbuf, unsigned int numindicies, IDirect3DIndexBuffer9 *ibuf)
{
float pushdepth;
extern cvar_t r_polygonoffset_submodel_factor;
// D3D9BE_Cull(0);//shaderstate.curshader->flags & (SHADER_CULL_FRONT | SHADER_CULL_BACK));
pushdepth = (shaderstate.curshader->polyoffset.factor + ((0/*shaderstate.flags & BEF_PUSHDEPTH*/)?r_polygonoffset_submodel_factor.value:0))/0xffff;
if (pushdepth != shaderstate.depthbias)
{
shaderstate.depthbias = pushdepth;
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_DEPTHBIAS, *(DWORD*)&shaderstate.depthbias);
}
IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_VERT, vbuf, 0, sizeof(vecV_t));
IDirect3DDevice9_SetIndices(pD3DDev9, ibuf);
@ -3185,6 +3260,7 @@ void D3D9BE_DrawWorld (qboolean drawworld, qbyte *vis)
if (drawworld)
{
float shaderstate_identitylighting;
BE_UploadLightmaps(false);
//make sure the world draws correctly
@ -3196,7 +3272,19 @@ void D3D9BE_DrawWorld (qboolean drawworld, qbyte *vis)
r_worldentity.axis[1][1] = 1;
r_worldentity.axis[2][2] = 1;
BE_SelectMode(BEM_STANDARD);
#ifdef RTLIGHTS
if (drawworld && r_shadow_realtime_world.ival)
shaderstate_identitylighting = r_shadow_realtime_world_lightmaps.value;
else
#endif
shaderstate_identitylighting = 1;
shaderstate_identitylighting *= r_refdef.hdr_value;
// shaderstate_identitylightmap = shaderstate.identitylighting / (1<<gl_overbright.ival);
if (shaderstate_identitylighting == 0)
BE_SelectMode(BEM_DEPTHDARK);
else
BE_SelectMode(BEM_STANDARD);
RSpeedRemark();
D3D9BE_SubmitMeshes(true, batches, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
@ -3212,6 +3300,8 @@ void D3D9BE_DrawWorld (qboolean drawworld, qbyte *vis)
}
#endif
BE_SelectMode(BEM_STANDARD);
D3D9BE_SubmitMeshes(true, batches, SHADER_SORT_DECAL, SHADER_SORT_COUNT);
}
else

View File

@ -101,7 +101,9 @@ qboolean D3D9_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips)
IDirect3DTexture9_LockRect(dt, i, &lock, NULL, D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD);
//can't do it in one go. pitch might contain padding or be upside down.
if (blocksize)
if (!mips->mip[i].data)
;
else if (blocksize)
{
if (lock.Pitch == ((mips->mip[i].width+3)/4)*blocksize)
//for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize)

View File

@ -560,9 +560,8 @@ static qboolean initD3D9Device(HWND hWnd, rendererstate_t *info, unsigned int de
rect.bottom = rect.top+d3dpp.BackBufferHeight;
AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, FALSE, 0);
MoveWindow(d3dpp.hDeviceWindow, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, false);
D3D9Shader_Init();
}
D3D9Shader_Init();
return true; //successful
}
else
@ -731,6 +730,8 @@ static qboolean D3D9_VID_Init(rendererstate_t *info, unsigned char *palette)
mouseactive = false;
}
// D3D9BE_Reset(false);
return true;
}
@ -741,6 +742,8 @@ static void (D3D9_VID_DeInit) (void)
/*final shutdown, kill the video stuff*/
if (pD3DDev9)
{
D3D9BE_Reset(true);
/*try and knock it back into windowed mode to avoid d3d bugs*/
d3dpp.Windowed = true;
IDirect3DDevice9_Reset(pD3DDev9, &d3dpp);
@ -906,6 +909,7 @@ static void (D3D9_SCR_UpdateScreen) (void)
{
case D3DERR_DEVICELOST:
//the user has task switched away from us or something, don't draw anything until they switch back to us
D3D9BE_Reset(true);
return;
case D3DERR_DEVICENOTRESET:
D3D9BE_Reset(true);
@ -916,7 +920,6 @@ static void (D3D9_SCR_UpdateScreen) (void)
Cmd_ExecuteString("vid_restart", RESTRICT_LOCAL);
return;
}
D3D9BE_Reset(false);
Cvar_ForceCallback(&v_gamma);
break;
@ -924,6 +927,8 @@ static void (D3D9_SCR_UpdateScreen) (void)
break;
}
D3D9BE_Reset(false);
if (scr_disabled_for_loading)
{
extern float scr_disabled_time;
@ -1035,8 +1040,6 @@ static void (D3D9_SCR_UpdateScreen) (void)
nohud = true;
}
else if (!nohud)
SCR_TileClear ();
SCR_DrawTwoDimensional(uimenu, nohud);

View File

@ -1309,8 +1309,6 @@ static void (D3D11_SCR_UpdateScreen) (void)
nohud = true;
}
else if (!nohud)
SCR_TileClear ();
SCR_DrawTwoDimensional(uimenu, nohud);

View File

@ -15244,6 +15244,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\client\snd_xaudio.c"
>
</File>
</Filter>
</Filter>
<Filter

View File

@ -1855,6 +1855,9 @@ void R_DrawGAliasShadowVolume(entity_t *e, vec3_t lightpos, float radius)
vec3_t lightorg;
int surfnum = 0;
if (qrenderer != QR_OPENGL)
return;
if (clmodel->engineflags & (MDLF_FLAME | MDLF_BOLT))
return;
if (r_noaliasshadows.ival)

View File

@ -926,7 +926,11 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi
void GL_CullFace(unsigned int sflags)
{
sflags ^= r_refdef.flipcull;
if (shaderstate.flags & BEF_FORCETWOSIDED)
sflags = 0;
else if (sflags)
sflags ^= r_refdef.flipcull;
#ifndef FORCESTATE
if (shaderstate.curcull == sflags)
return;
@ -2902,7 +2906,6 @@ static void DrawPass(const shaderpass_t *pass)
tmu++;
}
#endif
//might need to break the pass here
if (j > 1 && i != lastpass)
@ -2920,6 +2923,7 @@ static void DrawPass(const shaderpass_t *pass)
BE_SendPassBlendDepthMask(pass[i+1].shaderbits);
GenerateColourMods(&pass[i+1]);
}
#endif
}
}
@ -3931,26 +3935,7 @@ static void DrawMeshes(void)
}
flags = shaderstate.curshader->flags;
#ifndef FORCESTATE
if (shaderstate.curcull != ((flags^r_refdef.flipcull) & (SHADER_CULL_FRONT|SHADER_CULL_BACK)))
#endif
{
shaderstate.curcull = ((flags^r_refdef.flipcull) & (SHADER_CULL_FRONT|SHADER_CULL_BACK));
if (shaderstate.curcull & SHADER_CULL_FRONT)
{
qglEnable(GL_CULL_FACE);
qglCullFace(GL_FRONT);
}
else if (shaderstate.curcull & SHADER_CULL_BACK)
{
qglEnable(GL_CULL_FACE);
qglCullFace(GL_BACK);
}
else
{
qglDisable(GL_CULL_FACE);
}
}
GL_CullFace(flags & (SHADER_CULL_FRONT|SHADER_CULL_BACK));
#ifndef GLSLONLY
if (shaderstate.sourcevbo->coord2.gl.addr && (shaderstate.curshader->numdeforms || !shaderstate.curshader->prog))

View File

@ -1739,7 +1739,7 @@ int Font_LineWidth(conchar_t *start, conchar_t *end)
int x = 0;
struct font_s *font = curfont;
unsigned int codeflags, codepoint;
for (; start < end; start++)
for (; start < end; )
{
start = Font_Decode(start, &codeflags, &codepoint);
x = Font_CharEndCoord(font, x, codeflags, codepoint);

View File

@ -5180,7 +5180,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
LightPlane (hm->relightcontext, hm->lightthreadmem, styles, br->faces[j].lightdata, NULL, br->planes[j], br->faces[j].stdir, exactmins, exactmaxs, br->faces[j].lmbias, texsize, br->faces[j].lmscale); //special version that doesn't know what a face is or anything.
br->faces[j].relit = true;
}
if (br->faces[j].relit)
if (br->faces[j].relit && br->faces[j].lightmap >= 0)
{
int s,t;
qbyte *out, *in;
@ -5474,8 +5474,16 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
out->faces[oface].lmextents[k] = ceil((maxs[k])/out->faces[oface].lmscale)-out->faces[oface].lmbias[k]+1;
if (out->faces[oface].lmextents[k] > 128)
{ //surface is too large for lightmap data. just drop its resolution, because splitting the face in plane-defined geometry is a bad idea.
out->faces[oface].lmscale *= 2;
k = 0;
if (out->faces[oface].lmscale > 256)
{
out->faces[oface].relight = false;
k++;
}
else
{
out->faces[oface].lmscale *= 2;
k = 0;
}
}
else
k++;
@ -5483,8 +5491,13 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
out->faces[oface].lightmap = -1;
out->faces[oface].lmbase[0] = 0;
out->faces[oface].lmbase[1] = 0;
out->faces[oface].lightdata = BZ_Malloc(out->faces[oface].lmextents[0] * out->faces[oface].lmextents[1] * 3);
memset(out->faces[oface].lightdata, 0x3f, out->faces[oface].lmextents[0]*out->faces[oface].lmextents[1]*3);
if (out->faces[oface].relight)
{
out->faces[oface].lightdata = BZ_Malloc(out->faces[oface].lmextents[0] * out->faces[oface].lmextents[1] * 3);
memset(out->faces[oface].lightdata, 0x3f, out->faces[oface].lmextents[0]*out->faces[oface].lmextents[1]*3);
}
else
out->faces[oface].lightdata = NULL;
// Con_Printf("lm extents: %u %u (%i points)\n", out->faces[oface].lmextents[0], out->faces[oface].lmextents[1], numpoints);
oface++;
@ -5724,7 +5737,7 @@ static void *validateqcpointer(pubprogfuncs_t *prinst, size_t qcptr, size_t elem
PR_BIError(prinst, "brush: elementcount %u is too large\n", (unsigned int)elementcount);
return NULL;
}
if (qcptr < 0 || qcptr+(elementsize*elementcount) >= prinst->stringtablesize)
if (qcptr < 0 || qcptr+(elementsize*elementcount) > prinst->stringtablesize)
{
PR_BIError(prinst, "brush: invalid qc pointer\n");
return NULL;

View File

@ -34,6 +34,7 @@ extern cvar_t r_replacemodels;
extern cvar_t gl_lightmap_average;
extern cvar_t r_softwarebanding;
cvar_t mod_loadentfiles = CVAR("sv_loadentfiles", "1");
cvar_t mod_loadentfiles_dir = CVAR("sv_loadentfiles_dir", "");
cvar_t mod_external_vis = CVARD("mod_external_vis", "1", "Attempt to load .vis patches for quake maps, allowing transparent water to work properly.");
cvar_t mod_warnmodels = CVARD("mod_warnmodels", "1", "Warn if any models failed to load. Set to 0 if your mod is likely to lack optional models (like its in development)."); //set to 0 for hexen2 and its otherwise-spammy-as-heck demo.
cvar_t mod_litsprites = CVARD("mod_litsprites", "0", "If set to 1, sprites will be lit according to world lighting (including rtlights), like Tenebrae. Use EF_ADDITIVE or EF_FULLBRIGHT to make emissive sprites instead.");
@ -60,6 +61,7 @@ qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer, size_t fsize);
#endif
model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose);
static void Mod_PrintFormats_f(void);
static void Mod_SaveEntFile_f(void);
#ifdef MAP_DOOM
qboolean QDECL Mod_LoadDoomLevel(model_t *mod, void *buffer, size_t fsize);
@ -524,6 +526,7 @@ void Mod_Purge(enum mod_purge_e ptype)
mod->meshinfo = NULL;
mod->loadstate = MLS_NOTLOADED;
mod->submodelof = NULL;
mod->pvs = NULL;
mod->phs = NULL;
}
@ -559,7 +562,9 @@ void Mod_Init (qboolean initial)
Cvar_Register(&mod_warnmodels, "Graphical Nicaties");
Cvar_Register(&mod_litsprites, "Graphical Nicaties");
Cvar_Register(&mod_loadentfiles, NULL);
Cvar_Register(&mod_loadentfiles_dir, NULL);
Cvar_Register(&temp_lit2support, NULL);
Cmd_AddCommand("sv_saveentfile", Mod_SaveEntFile_f);
Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f);
}
@ -1717,7 +1722,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
if (!temp_lit2support.ival)
{
litdata = NULL;
Con_Printf("lit2 support is disabled, pending format finalisation.\n", litname);
Con_Printf("lit2 support is disabled, pending format finalisation (%s).\n", litname);
}
else if (loadmodel->numsurfaces != ql2->numsurfs)
{
@ -2017,6 +2022,49 @@ char *Mod_ParseWorldspawnKey(const char *ents, const char *key, char *buffer, si
return ""; //err...
}
static void Mod_SaveEntFile_f(void)
{
char fname[MAX_QPATH];
model_t *mod = NULL;
char *n = Cmd_Argv(1);
if (*n)
mod = Mod_ForName(n, MLV_WARN);
#ifndef CLIENTONLY
if (sv.state && !mod)
mod = sv.world.worldmodel;
#endif
#ifndef SERVERONLY
if (cls.state && !mod)
mod = cl.worldmodel;
#endif
if (mod && mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (!mod || mod->loadstate != MLS_LOADED)
{
Con_Printf("Map not loaded\n");
return;
}
if (!mod->entities)
{
Con_Printf("Map is not a map, and has no entities\n");
return;
}
if (*mod_loadentfiles_dir.string && !strncmp(mod->name, "maps/", 5))
{
Q_snprintfz(fname, sizeof(fname), "maps/%s/%s", mod_loadentfiles_dir.string, mod->name+5);
COM_StripExtension(fname, fname, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname));
}
else
{
COM_StripExtension(mod->name, fname, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname));
}
COM_WriteFile(fname, FS_GAMEONLY, mod->entities, strlen(mod->entities));
}
/*
=================
Mod_LoadEntities
@ -2031,6 +2079,16 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
if (!l->filelen)
return;
if (mod_loadentfiles.value && !loadmodel->entities && *mod_loadentfiles_dir.string)
{
if (!strncmp(loadmodel->name, "maps/", 5))
{
Q_snprintfz(fname, sizeof(fname), "maps/%s/%s", mod_loadentfiles_dir.string, loadmodel->name+5);
COM_StripExtension(fname, fname, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname));
loadmodel->entities = FS_LoadMallocGroupFile(&loadmodel->memgroup, fname, &sz);
}
}
if (mod_loadentfiles.value && !loadmodel->entities)
{
COM_StripExtension(loadmodel->name, fname, sizeof(fname));
@ -4726,6 +4784,7 @@ TRACE(("LoadBrushModel %i\n", __LINE__));
// Q_snprintfz (name, sizeof(name), "*%i", i+1);
nextmod = Mod_FindName (name);
*nextmod = *submod;
nextmod->submodelof = mod;
Q_strncpyz(nextmod->name, name, sizeof(nextmod->name));
submod = nextmod;
memset(&submod->memgroup, 0, sizeof(submod->memgroup));
@ -4835,7 +4894,29 @@ void Mod_LoadSpriteFrameShader(model_t *spr, int frame, int subframe, mspritefra
}
if (i == -1) // a ! in the filename makes it non-fullbright (and can also be lit by rtlights too).
shadertext = SPRITE_SHADER_MAIN SPRITE_SHADER_LIT SPRITE_SHADER_FOOTER;
{
shadertext =
"{\n"
"program defaultsprite\n"
"{\n"
"map $diffuse\n"
"blendfunc GL_SRC_ALPHA GL_ONE\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"}\n"
"surfaceparm noshadows\n"
"sort seethrough\n"
"bemode rtlight\n"
"{\n"
"program rtlight#NOBUMP\n"
"{\n"
"map $diffuse\n"
"blendfunc add\n"
"}\n"
"}\n"
"}\n"
;
}
else
shadertext = SPRITE_SHADER_MAIN SPRITE_SHADER_UNLIT SPRITE_SHADER_FOOTER;
frameinfo->shader = R_RegisterShader(name, SUF_NONE, shadertext);

View File

@ -177,7 +177,7 @@ m*_t structures are in-memory
#define DPEF_DOUBLESIDED_ (1<<15) //disables culling
#define DPEF_NOSELFSHADOW_ (1<<16) //doesn't cast shadows on any noselfshadow entities.
#define DPEF_DYNAMICMODELLIGHT_ (1<<17)
#define EF_UNUSED18 (1<<18)
#define EF_GREEN (1<<18)
#define EF_UNUSED19 (1<<19)
#define DPEF_RESTARTANIM_BIT_ (1<<20) //exact semantics seems odd
#define DPEF_TELEPORT_BIT_ (1<<21) //disable lerping while set
@ -370,7 +370,7 @@ typedef struct msurface_s
unsigned short numedges; // are backwards edges
unsigned short lmshift; //texels>>lmshift = lightmap samples.
short texturemins[2];
int texturemins[2];
short extents[2];
unsigned short light_s[MAXRLIGHTMAPS], light_t[MAXRLIGHTMAPS]; // gl lightmap coordinates
@ -854,6 +854,8 @@ typedef struct model_s
qboolean tainted;
qboolean pushdepth; // bsp submodels have this flag set so you don't get z fighting on co-planar surfaces.
struct model_s *submodelof;
modtype_t type;
fromgame_t fromgame;
@ -988,7 +990,7 @@ typedef struct model_s
#endif // __MODEL__
float RadiusFromBounds (vec3_t mins, vec3_t maxs);
//

View File

@ -546,7 +546,7 @@ void R_PushDlights (void)
//rtlight loading
#ifdef RTLIGHTS
void R_ImportRTLights(char *entlump)
qboolean R_ImportRTLights(char *entlump)
{
typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
@ -556,6 +556,7 @@ void R_ImportRTLights(char *entlump)
float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
char key[256], value[8192];
int nest;
qboolean okay = false;
COM_Parse(entlump);
if (!strcmp(com_token, "Version"))
@ -743,7 +744,10 @@ void R_ImportRTLights(char *entlump)
{
//tenebrae compat. don't generate rtlights automagically if the world entity specifies this.
if (atoi(value))
return;
{
okay = true;
return okay;
}
}
}
if (!islight)
@ -783,7 +787,7 @@ void R_ImportRTLights(char *entlump)
break;
}
VectorAdd(origin, originhack, origin);
if (radius >= 1)
if (radius >= 1 && !(cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, origin) & FTECONTENTS_SOLID))
{
dlight_t *dl = CL_AllocSlight();
if (!dl)
@ -803,11 +807,15 @@ void R_ImportRTLights(char *entlump)
dl->lightcolourscales[2] = r_editlights_import_specular.value;
if (skin >= 16)
R_LoadNumberedLightTexture(dl, skin);
okay = true;
}
}
return okay;
}
void R_LoadRTLights(void)
qboolean R_LoadRTLights(void)
{
dlight_t *dl;
char fname[MAX_QPATH];
@ -954,6 +962,7 @@ void R_LoadRTLights(void)
}
file = end+1;
}
return !!file;
}
void R_SaveRTLights_f(void)
@ -995,7 +1004,7 @@ void R_SaveRTLights_f(void)
light->radius, light->color[0], light->color[1], light->color[2],
light->style-1,
light->cubemapname, light->corona,
ang[0], ang[1], ang[2],
anglemod(-ang[0]), ang[1], ang[2],
light->coronascale, light->lightcolourscales[0], light->lightcolourscales[1], light->lightcolourscales[2], light->flags&(LFLAG_NORMALMODE|LFLAG_REALTIMEMODE|LFLAG_CREPUSCULAR),
light->rotation[0],light->rotation[1],light->rotation[2],light->fov
));
@ -1025,7 +1034,7 @@ void R_StaticEntityToRTLight(int i)
if (!state->light[0] && !state->light[1] && !state->light[2])
VectorSet(dl->color, 1, 1, 1);
dl->flags = 0;
dl->flags |= LFLAG_REALTIMEMODE;
dl->flags |= LFLAG_NORMALMODE|LFLAG_REALTIMEMODE;
dl->flags |= (state->lightpflags & PFLAGS_NOSHADOW)?LFLAG_NOSHADOWS:0;
if (state->lightpflags & PFLAGS_CORONA)
dl->corona = 1;
@ -1209,7 +1218,7 @@ void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_a
VectorCopy(direction, res_dir);
}
int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
static int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
{
int r;
float front, back, frac;
@ -1361,7 +1370,7 @@ int R_LightPoint (vec3_t p)
#ifdef PEXT_LIGHTSTYLECOL
float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start, vec3_t end)
{
static float l[6];
float *r;
@ -1377,7 +1386,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
float scale, overbright;
int maps;
if (cl.worldmodel->fromgame == fg_quake2)
if (mod->fromgame == fg_quake2)
{
if (node->contents != -1)
return NULL; // solid
@ -1394,7 +1403,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
side = front < 0;
if ( (back < 0) == side)
return GLRecursiveLightPoint3C (node->children[side], start, end);
return GLRecursiveLightPoint3C (mod, node->children[side], start, end);
frac = front / (front-back);
mid[0] = start[0] + (end[0] - start[0])*frac;
@ -1402,7 +1411,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
mid[2] = start[2] + (end[2] - start[2])*frac;
// go down front side
r = GLRecursiveLightPoint3C (node->children[side], start, mid);
r = GLRecursiveLightPoint3C (mod, node->children[side], start, mid);
if (r && r[0]+r[1]+r[2] >= 0)
return r; // hit something
@ -1413,7 +1422,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
VectorCopy (mid, lightspot);
lightplane = plane;
surf = cl.worldmodel->surfaces + node->firstsurface;
surf = mod->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
if (surf->flags & SURF_DRAWTILED)
@ -1450,11 +1459,11 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
if (lightmap)
{
overbright = 1/255.0f;
if (cl.worldmodel->deluxdata)
if (mod->deluxdata)
{
if (cl.worldmodel->engineflags & MDLF_RGBLIGHTING)
if (mod->engineflags & MDLF_RGBLIGHTING)
{
deluxmap = surf->samples - cl.worldmodel->lightdata + cl.worldmodel->deluxdata;
deluxmap = surf->samples - mod->lightdata + mod->deluxdata;
lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3;
deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3;
@ -1480,7 +1489,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
}
else
{
deluxmap = (surf->samples - cl.worldmodel->lightdata)*3 + cl.worldmodel->deluxdata;
deluxmap = (surf->samples - mod->lightdata)*3 + mod->deluxdata;
lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds);
deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3;
@ -1507,7 +1516,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
}
else
{
if (cl.worldmodel->engineflags & MDLF_RGBLIGHTING)
if (mod->engineflags & MDLF_RGBLIGHTING)
{
lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3;
for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ;
@ -1547,7 +1556,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
}
// go down back side
return GLRecursiveLightPoint3C (node->children[!side], mid, end);
return GLRecursiveLightPoint3C (mod, node->children[!side], mid, end);
}
#endif
@ -1558,7 +1567,7 @@ void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse,
float *r;
extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_lightmaps;
if (!cl.worldmodel->lightdata || r_fullbright.ival)
if (!model->lightdata || r_fullbright.ival)
{
res_diffuse[0] = 0;
res_diffuse[1] = 0;
@ -1579,7 +1588,7 @@ void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse,
end[1] = point[1];
end[2] = point[2] - 2048;
r = GLRecursiveLightPoint3C(model->rootnode, point, end);
r = GLRecursiveLightPoint3C(model, model->rootnode, point, end);
if (r == NULL)
{
res_diffuse[0] = 0;

View File

@ -1735,6 +1735,13 @@ void GLR_RenderView (void)
r_refdef.flags |= RDF_WATERWARP; //try fullscreen warp instead if we can
}
if (!r_refdef.globalfog.density)
{
int fogtype = ((r_refdef.flags & RDF_UNDERWATER) && cl.fog[1].density)?1:0;
CL_BlendFog(&r_refdef.globalfog, &cl.oldfog[fogtype], realtime, &cl.fog[fogtype]);
r_refdef.globalfog.density /= 64; //FIXME
}
if (!(r_refdef.flags & RDF_NOWORLDMODEL) && (*r_postprocshader.string))
{
custompostproc = R_RegisterCustom(r_postprocshader.string, SUF_NONE, NULL, NULL);

View File

@ -1488,7 +1488,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype)
if (file)
{
Con_DPrintf("Loaded %s from disk\n", basicname);
Con_DPrintf("Loaded %s from disk\n", va(sh_config.progpath, basicname));
g->failed = !Shader_LoadPermutations(g->name, &g->prog, file, qrtype, 0, blobname);
FS_FreeFile(file);
return;
@ -3029,6 +3029,7 @@ void Shader_Free (shader_t *shader)
if (shader->skydome)
Z_Free (shader->skydome);
shader->skydome = NULL;
while (shader->clutter)
{
void *t = shader->clutter;
@ -5673,6 +5674,44 @@ void Shader_ShowShader_f(void)
Con_Printf("Shader \"%s\" is not loaded\n", sourcename);
}
void Shader_TouchTextures(void)
{
int i, j, k;
shader_t *s;
shaderpass_t *p;
texnums_t *t;
for (i = 0; i < r_numshaders; i++)
{
s = r_shaders[i];
if (!s || !s->uses)
continue;
for (j = 0; j < s->numpasses; j++)
{
p = &s->passes[j];
for (k = 0; k < countof(p->anim_frames); k++)
if (p->anim_frames[k])
p->anim_frames[k]->regsequence = r_regsequence;
}
for (j = 0; j < max(1,s->numdefaulttextures); j++)
{
t = &s->defaulttextures[j];
if (t->base)
t->base->regsequence = r_regsequence;
if (t->bump)
t->bump->regsequence = r_regsequence;
if (t->fullbright)
t->fullbright->regsequence = r_regsequence;
if (t->specular)
t->specular->regsequence = r_regsequence;
if (t->upperoverlay)
t->upperoverlay->regsequence = r_regsequence;
if (t->loweroverlay)
t->loweroverlay->regsequence = r_regsequence;
}
}
}
void Shader_DoReload(void)
{
shader_t *s;

View File

@ -2649,6 +2649,9 @@ static void Sh_DrawBrushModelShadow(dlight_t *dl, entity_t *e)
model_t *model;
msurface_t *surf;
if (qrenderer != QR_OPENGL)
return;
if (BE_LightCullModel(e->origin, e->model))
return;
@ -3054,10 +3057,9 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3],
/*draw the shadows*/
Sh_DrawStencilLightShadows(dl, lvis, vvis, false);
//disable stencil writing, switch culling back to normal
//disable stencil writing
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_TWOSIDEDSTENCILMODE, false);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_CW);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_STENCILFUNC, D3DCMP_EQUAL);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_STENCILREF, sref);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_STENCILMASK, ~0);
@ -3250,6 +3252,7 @@ void Sh_PurgeShadowMeshes(void)
maxedge = 0;
}
void R_StaticEntityToRTLight(int i);
void Sh_PreGenerateLights(void)
{
unsigned int ignoreflags;
@ -3260,16 +3263,22 @@ void Sh_PreGenerateLights(void)
int i;
r_shadow_realtime_world_lightmaps.value = atof(r_shadow_realtime_world_lightmaps.string);
if (r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival)
if ((r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival) && rtlights_max == RTL_FIRST)
{
if (RTL_FIRST == rtlights_max)
R_LoadRTLights();
if (RTL_FIRST == rtlights_max)
R_ImportRTLights(cl.worldmodel->entities);
if (RTL_FIRST == rtlights_max && r_shadow_realtime_world.ival)
qboolean okay = false;
if (!okay)
okay |= R_LoadRTLights();
if (!okay)
okay |= R_ImportRTLights(cl.worldmodel->entities);
if (!okay && r_shadow_realtime_world.ival && r_shadow_realtime_world_lightmaps.value != 1)
{
r_shadow_realtime_world_lightmaps.value = 1;
Con_Printf(CON_ERROR "No lights detected in map. Disabling realtime lights.\n");
Con_Printf(CON_WARNING "No lights detected in map.\n");
}
for (i = 0; i < cl.num_statics; i++)
{
R_StaticEntityToRTLight(i);
}
}
@ -3348,12 +3357,10 @@ void Sh_CheckSettings(void)
#endif
#ifdef D3D9QUAKE
case QR_DIRECT3D9:
#ifndef GLQUAKE
canshadowless = true;
//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.
canstencil = true;
#endif
break;
#endif
#ifdef D3D11QUAKE
@ -3391,7 +3398,8 @@ void Sh_CheckSettings(void)
//only one shadow method
if (!!r_shadow_shadowmapping.ival != cansmap)
{
Con_Printf("Missing driver extensions: forcing shadowmapping %s.\n", cansmap?"on":"off");
if (r_shadow_shadowmapping.ival && ((r_shadow_realtime_world.ival&&r_shadow_realtime_world_shadows.ival)||(r_shadow_realtime_dlight.ival&&r_shadow_realtime_dlight_shadows.ival)))
Con_Printf("Missing driver extensions: forcing shadowmapping %s.\n", cansmap?"on":"off");
r_shadow_shadowmapping.ival = cansmap;
}
}
@ -3519,6 +3527,9 @@ void Sh_DrawLights(qbyte *vis)
if (colour[0] < 0.001 && colour[1] < 0.001 && colour[2] < 0.001)
continue; //just switch these off.
if (!dl->lightcolourscales[0] && !dl->lightcolourscales[1] && !dl->lightcolourscales[2])
continue; //these lights are just coronas.
if (dl->rotation[0] || dl->rotation[1] || dl->rotation[2])
{ //auto-rotating (static) rtlights
vec3_t rot;

View File

@ -2632,7 +2632,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
if (isPlugin >= 2)
{
fprintf(stdout, "refocuswindow %#p\n", mainwindow);
fprintf(stdout, "refocuswindow "fPRIp"\n", mainwindow);
fflush(stdout);
}

View File

@ -47,7 +47,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
void D3D9_Set2D (void);
float RadiusFromBounds (vec3_t mins, vec3_t maxs);
void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2);
void ClearBounds (vec3_t mins, vec3_t maxs);
@ -411,8 +410,8 @@ void GLR_MarkQ2Lights (dlight_t *light, int bit, mnode_t *node);
#endif
void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir);
void R_ReloadRTLights_f(void);
void R_LoadRTLights(void);
void R_ImportRTLights(char *entlump);
qboolean R_LoadRTLights(void);
qboolean R_ImportRTLights(char *entlump);
void R_SaveRTLights_f(void);
//doom

View File

@ -641,6 +641,7 @@ mfog_t *Mod_FogForOrigin(model_t *wmodel, vec3_t org);
#define BEF_NOSHADOWS 128 //don't appear in shadows
#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.
#define BEF_FORCETWOSIDED 1024 //more evilness.
typedef struct
{

View File

@ -578,7 +578,7 @@ reeval:
glob = NULL; //try to derestrict it.
callerprogs=pr_typecurrent; //so we can revert to the right caller.
callerprogs=prinst.pr_typecurrent; //so we can revert to the right caller.
newpr = (fnum & 0xff000000)>>24; //this is the progs index of the callee
fnum &= ~0xff000000; //the callee's function index.
@ -607,7 +607,7 @@ reeval:
if (newf->first_statement <= 0)
{ // negative statements are built in functions
/*calling a builtin in another progs may affect that other progs' globals instead, is the theory anyway, so args and stuff need to move over*/
if (pr_typecurrent != 0)
if (prinst.pr_typecurrent != 0)
{
//builtins quite hackily refer to only a single global.
//for builtins to affect the globals of other progs, we need to first switch to the progs that it will affect, so they'll be correct when we switch back

View File

@ -14,12 +14,12 @@ void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount, char *name)
ammount = sizeof(prmemb_t)+((ammount + 3)&~3);
mem = progfuncs->funcs.parms->memalloc(ammount);
memset(mem, 0, ammount);
mem->prev = memb;
if (!memb)
mem->prev = prinst.memblocks;
if (!prinst.memblocks)
mem->level = 1;
else
mem->level = ((prmemb_t *)memb)->level+1;
memb = mem;
mem->level = ((prmemb_t *)prinst.memblocks)->level+1;
prinst.memblocks = mem;
return ((char *)mem)+sizeof(prmemb_t);
}
@ -30,18 +30,18 @@ void *PDECL QC_HunkAlloc(pubprogfuncs_t *ppf, int ammount, char *name)
int PRHunkMark(progfuncs_t *progfuncs)
{
return ((prmemb_t *)memb)->level;
return ((prmemb_t *)prinst.memblocks)->level;
}
void PRHunkFree(progfuncs_t *progfuncs, int mark)
{
prmemb_t *omem;
while(memb)
while(prinst.memblocks)
{
if (memb->level <= mark)
if (prinst.memblocks->level <= mark)
return;
omem = memb;
memb = memb->prev;
omem = prinst.memblocks;
prinst.memblocks = prinst.memblocks->prev;
externs->memfree(omem);
}
return;
@ -52,7 +52,7 @@ void PRAddressableRelocate(progfuncs_t *progfuncs, char *oldb, char *newb, int o
{
unsigned int i;
edictrun_t *e;
for (i=0 ; i<maxedicts; i++)
for (i=0 ; i<prinst.maxedicts; i++)
{
e = (edictrun_t *)(prinst.edicttable[i]);
if (e && (char*)e->fields >= oldb && (char*)e->fields < oldb+oldlen)
@ -62,7 +62,7 @@ void PRAddressableRelocate(progfuncs_t *progfuncs, char *oldb, char *newb, int o
if (progfuncs->funcs.stringtable >= oldb && progfuncs->funcs.stringtable < oldb+oldlen)
progfuncs->funcs.stringtable = (progfuncs->funcs.stringtable - oldb) + newb;
for (i=0; i < maxprogs; i++)
for (i=0; i < prinst.maxprogs; i++)
{
if ((char*)prinst.progstate[i].globals >= oldb && (char*)prinst.progstate[i].globals < oldb+oldlen)
prinst.progstate[i].globals = (float*)(((char*)prinst.progstate[i].globals - oldb) + newb);
@ -433,7 +433,7 @@ void PRAddressableFlush(progfuncs_t *progfuncs, size_t totalammount)
int PDECL PR_InitEnts(pubprogfuncs_t *ppf, int max_ents)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
maxedicts = max_ents;
prinst.maxedicts = max_ents;
sv_num_edicts = 0;
@ -447,19 +447,19 @@ int PDECL PR_InitEnts(pubprogfuncs_t *ppf, int max_ents)
}
#endif
max_fields_size = fields_size;
prinst.max_fields_size = prinst.fields_size;
prinst.edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *), "edicttable");
prinst.edicttable = PRHunkAlloc(progfuncs, prinst.maxedicts*sizeof(struct edicts_s *), "edicttable");
sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize, "edict0");
prinst.edicttable[0] = sv_edicts;
((edictrun_t*)prinst.edicttable[0])->fields = PRAddressableExtend(progfuncs, NULL, fields_size, max_fields_size-fields_size);
((edictrun_t*)prinst.edicttable[0])->fields = PRAddressableExtend(progfuncs, NULL, prinst.fields_size, prinst.max_fields_size-prinst.fields_size);
QC_ClearEdict(&progfuncs->funcs, sv_edicts);
sv_num_edicts = 1;
if (externs->entspawn)
externs->entspawn((struct edict_s *)sv_edicts, false);
return max_fields_size;
return prinst.max_fields_size;
}
edictrun_t tempedict; //used as a safty buffer
static float tempedictfields[2048];
@ -470,13 +470,13 @@ static void PDECL PR_Configure (pubprogfuncs_t *ppf, size_t addressable_size, in
unsigned int i;
edictrun_t *e;
max_fields_size=0;
fields_size = 0;
prinst.max_fields_size=0;
prinst.fields_size = 0;
progfuncs->funcs.stringtable = 0;
QC_StartShares(progfuncs);
QC_InitShares(progfuncs);
for ( i=1 ; i<maxedicts; i++)
for ( i=1 ; i<prinst.maxedicts; i++)
{
e = (edictrun_t *)(prinst.edicttable[i]);
prinst.edicttable[i] = NULL;
@ -506,15 +506,15 @@ static void PDECL PR_Configure (pubprogfuncs_t *ppf, size_t addressable_size, in
}
*/
maxprogs = max_progs;
pr_typecurrent=-1;
prinst.maxprogs = max_progs;
prinst.pr_typecurrent=-1;
PR_FreeAllTemps(progfuncs);
prinst.reorganisefields = false;
prinst.profiling = profiling;
maxedicts = 1;
prinst.maxedicts = 1;
prinst.edicttable = &sv_edicts;
sv_num_edicts = 1; //set up a safty buffer so things won't go horribly wrong too often
sv_edicts=(struct edict_s *)&tempedict;
@ -560,7 +560,7 @@ int PDECL PR_GetFuncArgCount(pubprogfuncs_t *ppf, func_t func)
pnum = (func & 0xff000000)>>24;
fnum = (func & 0x00ffffff);
if (pnum >= (unsigned)maxprogs || !pr_progstate[pnum].functions)
if (pnum >= prinst.maxprogs || !pr_progstate[pnum].functions)
return -1;
else if (fnum >= pr_progstate[pnum].progs->numfunctions)
return -1;
@ -577,7 +577,7 @@ func_t PDECL PR_FindFunc(pubprogfuncs_t *ppf, const char *funcname, progsnum_t p
mfunction_t *f=NULL;
if (pnum == PR_ANY)
{
for (pnum = 0; (unsigned)pnum < maxprogs; pnum++)
for (pnum = 0; (unsigned)pnum < prinst.maxprogs; pnum++)
{
if (!pr_progstate[pnum].progs)
continue;
@ -588,7 +588,7 @@ func_t PDECL PR_FindFunc(pubprogfuncs_t *ppf, const char *funcname, progsnum_t p
}
else if (pnum == PR_ANYBACK) //run backwards
{
for (pnum = maxprogs-1; pnum >= 0; pnum--)
for (pnum = prinst.maxprogs-1; pnum >= 0; pnum--)
{
if (!pr_progstate[pnum].progs)
continue;
@ -634,10 +634,10 @@ void PDECL QC_FindPrefixedGlobals(pubprogfuncs_t *ppf, int pnum, char *prefix, v
int len = strlen(prefix);
if (pnum == PR_CURRENT)
pnum = pr_typecurrent;
pnum = prinst.pr_typecurrent;
if (pnum == PR_ANY)
{
for (pnum = 0; (unsigned)pnum < maxprogs; pnum++)
for (pnum = 0; (unsigned)pnum < prinst.maxprogs; pnum++)
{
if (!pr_progstate[pnum].progs)
continue;
@ -679,11 +679,11 @@ eval_t *PDECL PR_FindGlobal(pubprogfuncs_t *ppf, const char *globname, progsnum_
ddef16_t *var16;
ddef32_t *var32;
if (pnum == PR_CURRENT)
pnum = pr_typecurrent;
pnum = prinst.pr_typecurrent;
if (pnum == PR_ANY)
{
eval_t *ev;
for (i = 0; i < maxprogs; i++)
for (i = 0; i < prinst.maxprogs; i++)
{
if (!pr_progstate[i].progs)
continue;
@ -693,7 +693,7 @@ eval_t *PDECL PR_FindGlobal(pubprogfuncs_t *ppf, const char *globname, progsnum_
}
return NULL;
}
if (pnum < 0 || (unsigned)pnum >= maxprogs || !pr_progstate[pnum].progs)
if (pnum < 0 || (unsigned)pnum >= prinst.maxprogs || !pr_progstate[pnum].progs)
return NULL;
switch(pr_progstate[pnum].structtype)
{
@ -801,7 +801,7 @@ eval_t *PDECL QC_GetEdictFieldValue(pubprogfuncs_t *ppf, struct edict_s *ed, cha
struct edict_s *PDECL ProgsToEdict (pubprogfuncs_t *ppf, int progs)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if ((unsigned)progs >= (unsigned)maxedicts)
if ((unsigned)progs >= (unsigned)prinst.maxedicts)
{
printf("Bad entity index %i\n", progs);
if (pr_depth)
@ -1178,7 +1178,7 @@ pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf, pbool resetprofiles)
cpufrequency = Sys_GetClockRate();
for (i = 0; i < maxprogs; i++)
for (i = 0; i < prinst.maxprogs; i++)
{
ps = &pr_progstate[i];
if (ps->progs == NULL) //we havn't loaded it yet, for some reason

View File

@ -381,11 +381,13 @@ enum qcop_e {
OP_BITCLR_I,
OP_ADD_SI,
OP_ADD_IS,
OP_ADD_PF,
OP_ADD_FP,
OP_ADD_PI,
OP_ADD_IP,
OP_SUB_SI,
OP_SUB_PF,
OP_SUB_PI,
@ -395,12 +397,12 @@ enum qcop_e {
OP_MOD_I,
OP_MOD_V,
OP_BITXOR_F, //140
OP_BITXOR_F,
OP_RSHIFT_F,
OP_LSHIFT_F,
OP_AND_ANY,
OP_OR_ANY, //190
OP_OR_ANY,
OP_NUMOPS
};

View File

@ -24,7 +24,7 @@ void PDECL QC_ClearEdict (pubprogfuncs_t *ppf, struct edict_s *ed)
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
edictrun_t *e = (edictrun_t *)ed;
int num = e->entnum;
memset (e->fields, 0, fields_size);
memset (e->fields, 0, prinst.fields_size);
e->isfree = false;
e->entnum = num;
}
@ -35,7 +35,7 @@ edictrun_t *ED_AllocIntoTable (progfuncs_t *progfuncs, int num)
prinst.edicttable[num] = *(struct edict_s **)&e = (void*)externs->memalloc(externs->edictsize);
memset(e, 0, externs->edictsize);
e->fields = PRAddressableExtend(progfuncs, NULL, fields_size, 0);
e->fields = PRAddressableExtend(progfuncs, NULL, prinst.fields_size, 0);
e->entnum = num;
QC_ClearEdict(&progfuncs->funcs, (struct edict_s*)e);
@ -80,7 +80,7 @@ struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf)
}
}
if (i >= maxedicts-1) //try again, but use timed out ents.
if (i >= prinst.maxedicts-1) //try again, but use timed out ents.
{
for ( i=0 ; i<sv_num_edicts ; i+=STEP)
{
@ -100,17 +100,17 @@ struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf)
}
}
if (i >= maxedicts-2)
if (i >= prinst.maxedicts-2)
{
PR_RunWarning(&progfuncs->funcs, "Running out of edicts\n");
}
if (i >= maxedicts-1)
if (i >= prinst.maxedicts-1)
{
int size;
char *buf;
buf = PR_SaveEnts(&progfuncs->funcs, NULL, &size, 0, 0);
progfuncs->funcs.parms->WriteFile("edalloc.dump", buf, size);
Sys_Error ("ED_Alloc: no free edicts (max is %i)", maxedicts);
Sys_Error ("ED_Alloc: no free edicts (max is %i)", prinst.maxedicts);
}
}
@ -456,14 +456,14 @@ mfunction_t *ED_FindFunction (progfuncs_t *progfuncs, const char *name, progsnum
if (fromprogs>=0)
pnum = fromprogs;
else
pnum = pr_typecurrent;
pnum = prinst.pr_typecurrent;
}
*prnum = pnum;
}
else
pnum = pr_typecurrent;
pnum = prinst.pr_typecurrent;
if ((unsigned)pnum > (unsigned)maxprogs)
if ((unsigned)pnum > (unsigned)prinst.maxprogs)
{
printf("Progsnum %i out of bounds\n", pnum);
return NULL;
@ -560,7 +560,7 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool v
QC_snprintfz (line, sizeof(line), "NULL function");
else
{
if ((val->function & 0xff000000)>>24 >= (unsigned)maxprogs || !pr_progstate[(val->function & 0xff000000)>>24].functions)
if ((val->function & 0xff000000)>>24 >= prinst.maxprogs || !pr_progstate[(val->function & 0xff000000)>>24].functions)
QC_snprintfz (line, sizeof(line), "Bad function %i:%i", (val->function & 0xff000000)>>24, val->function & ~0xff000000);
else
{
@ -696,7 +696,7 @@ char *PDECL PR_UglyValueString (pubprogfuncs_t *ppf, etype_t type, eval_t *val)
break;
case ev_function:
i = (val->function & 0xff000000)>>24; //progs number
if ((unsigned)i >= maxprogs || !pr_progstate[(unsigned)i].progs)
if ((unsigned)i >= prinst.maxprogs || !pr_progstate[(unsigned)i].progs)
sprintf (line, "BAD FUNCTION INDEX: %i", val->function);
else
{
@ -1445,7 +1445,7 @@ char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, int *bufofs, int bufmax
unsigned int j;
const char *name;
int type;
int curprogs = pr_typecurrent;
int curprogs = prinst.pr_typecurrent;
int len;
switch(current_progstate->structtype)
{
@ -1693,7 +1693,7 @@ char *SaveCallStack (progfuncs_t *progfuncs, char *buf, int *bufofs, int bufmax)
AddS ("\t}\n");
if (i == pr_depth)
globalbase = localstack + localstack_used - f->locals;
globalbase = prinst.localstack + prinst.localstack_used - f->locals;
else
globalbase -= f->locals;
}
@ -1726,12 +1726,12 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax,
//engine will need to store references to progs type and will need to preload the progs and inti the ents itself before loading.
//Make sure there is only 1 progs loaded.
for (a = 1; a < maxprogs; a++)
for (a = 1; a < prinst.maxprogs; a++)
{
if (pr_progstate[a].progs)
break;
}
if (!pr_progstate[0].progs || a != maxprogs) //the state of the progs wasn't Q1 compatible.
if (!pr_progstate[0].progs || a != prinst.maxprogs) //the state of the progs wasn't Q1 compatible.
{
externs->memfree(buffree);
return NULL;
@ -1740,7 +1740,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax,
//write the globals
AddS ("{\n");
oldprogs = pr_typecurrent;
oldprogs = prinst.pr_typecurrent;
PR_SwitchProgs(progfuncs, 0);
ED_WriteGlobals(progfuncs, buf, bufofs, bufmax);
@ -1769,16 +1769,16 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax,
if (alldata)
{
AddS("general {\n");
AddS(qcva("\"maxprogs\" \"%i\"\n", maxprogs));
AddS(qcva("\"maxprogs\" \"%i\"\n", prinst.maxprogs));
// AddS(qcva("\"maxentities\" \"%i\"\n", maxedicts));
// AddS(qcva("\"mem\" \"%i\"\n", hunksize));
// AddS(qcva("\"crc\" \"%i\"\n", header_crc));
AddS(qcva("\"numentities\" \"%i\"\n", sv_num_edicts));
AddS("}\n");
oldprogs = pr_typecurrent;
oldprogs = prinst.pr_typecurrent;
for (a = 0; a < maxprogs; a++)
for (a = 0; a < prinst.maxprogs; a++)
{
if (!pr_progstate[a].progs)
continue;
@ -1798,7 +1798,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax,
AddS("}\n");
}
for (a = 0; a < maxprogs; a++) //I would mix, but external functions rely on other progs being loaded
for (a = 0; a < prinst.maxprogs; a++) //I would mix, but external functions rely on other progs being loaded
{
if (!pr_progstate[a].progs)
continue;
@ -1892,7 +1892,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
{
if (entsize == 0 && resethunk) //edicts have not yet been initialized, and this is a compleate load (memsize has been set)
{
entsize = PR_InitEnts(&progfuncs->funcs, maxedicts);
entsize = PR_InitEnts(&progfuncs->funcs, prinst.maxedicts);
// sv_num_edicts = numents;
for (num = 0; num < numents; num++)
@ -1933,7 +1933,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (killonspawnflags)
{
var = QC_GetEdictFieldValue (&progfuncs->funcs, (struct edict_s *)&ed, "spawnflags", &spawnflagscache);
var = QC_GetEdictFieldValue (&progfuncs->funcs, (struct edict_s *)&ed, "spawnflags", &prinst.spawnflagscache);
if (var)
{
if ((int)var->_float & (int)killonspawnflags)
@ -2006,7 +2006,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
{
if (entsize == 0 && resethunk) //by the time we parse some globals, we MUST have loaded all progs
{
entsize = PR_InitEnts(&progfuncs->funcs, maxedicts);
entsize = PR_InitEnts(&progfuncs->funcs, prinst.maxedicts);
// sv_num_edicts = numents;
for (num = 0; num < numents; num++)
@ -2083,7 +2083,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
QC_StartShares(progfuncs);
// QC_InitShares(); //forget stuff
// pr_edict_size = 0;
max_fields_size=0;
prinst.max_fields_size=0;
file = QCC_COM_Parse(file);
if (qcc_token[0] != '{')
@ -2096,7 +2096,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
Sys_Error("EOF in general block");
if (!strcmp("maxprogs", qcc_token)) //check key get and save values
{file = QCC_COM_Parse(file); maxprogs = atoi(qcc_token);}
{file = QCC_COM_Parse(file); prinst.maxprogs = atoi(qcc_token);}
// else if (!strcmp("maxentities", com_token))
// {file = QCC_COM_Parse(file); maxedicts = atoi(qcc_token);}
// else if (!strcmp("mem", com_token))
@ -2129,8 +2129,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
PRAddressableFlush(progfuncs, 0);
resethunk=true;
pr_progstate = PRHunkAlloc(progfuncs, sizeof(progstate_t) * maxprogs, "progstatetable");
pr_typecurrent=0;
pr_progstate = PRHunkAlloc(progfuncs, sizeof(progstate_t) * prinst.maxprogs, "progstatetable");
prinst.pr_typecurrent=0;
sv_num_edicts = 1; //set up a safty buffer so things won't go horribly wrong too often
sv_edicts=(struct edict_s *)&tempedict;
@ -2206,7 +2206,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (entsize == 0 && resethunk) //edicts have not yet been initialized, and this is a compleate load (memsize has been set)
{
entsize = PR_InitEnts(&progfuncs->funcs, maxedicts);
entsize = PR_InitEnts(&progfuncs->funcs, prinst.maxedicts);
// sv_num_edicts = numents;
for (num = 0; num < numents; num++)
@ -2232,7 +2232,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (killonspawnflags)
{
var = QC_GetEdictFieldValue (&progfuncs->funcs, (struct edict_s *)ed, "spawnflags", &spawnflagscache);
var = QC_GetEdictFieldValue (&progfuncs->funcs, (struct edict_s *)ed, "spawnflags", &prinst.spawnflagscache);
if (var)
{
if ((int)var->_float & (int)killonspawnflags)
@ -2311,7 +2311,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
//only warn on the first occurence of the classname, don't spam.
int i;
const char *fnc = PR_StringToNative(&progfuncs->funcs, var->string);
if (pr_typecurrent >= 0)
if (prinst.pr_typecurrent >= 0)
for (i = 0; i < sizeof(spawnwarned)/sizeof(spawnwarned[0]); i++)
{
if (!spawnwarned[i])
@ -2349,7 +2349,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
return entsize;
}
else
return max_fields_size;
return prinst.max_fields_size;
}
//FIXME: maxsize is ignored.
@ -2630,7 +2630,7 @@ int PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstate_
// for (i=0 ; i<GEFV_CACHESIZE ; i++)
// gefvCache[i].field[0] = 0;
memset(&spawnflagscache, 0, sizeof(evalc_t));
memset(&prinst.spawnflagscache, 0, sizeof(evalc_t));
if (externs->autocompile == PR_COMPILEALWAYS) //always compile before loading
{
@ -2751,7 +2751,7 @@ retry:
if (!trysleft) //the progs exists, let's just be happy about it.
printf("Progs is out of date and uncompilable\n");
if (externs->CheckHeaderCrc && !externs->CheckHeaderCrc(&progfuncs->funcs, pr_typecurrent, pr_progs->crc))
if (externs->CheckHeaderCrc && !externs->CheckHeaderCrc(&progfuncs->funcs, prinst.pr_typecurrent, pr_progs->crc))
{
// printf ("%s system vars have been modified, progdefs.h is out of date\n", filename);
PRHunkFree(progfuncs, hmark);
@ -3048,7 +3048,7 @@ retry:
else
type = fld16[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL);
if (progfuncs->funcs.fieldadjust && !pr_typecurrent) //we need to make sure all fields appear in their original place.
if (progfuncs->funcs.fieldadjust && !prinst.pr_typecurrent) //we need to make sure all fields appear in their original place.
QC_RegisterFieldVar(&progfuncs->funcs, type, fld16[i].s_name+pr_strings, 4*(fld16[i].ofs+progfuncs->funcs.fieldadjust), -1);
else if (type == ev_vector) //emit vector vars early, so their fields cannot be alocated before the vector itself. (useful against scramblers)
{
@ -3073,14 +3073,14 @@ retry:
nf->progsofs = fld16[i].ofs;
nf->ofs = fld16[i].ofs;
if (fields_size < (nf->ofs+type_size[nf->type])*4)
fields_size = (nf->ofs+type_size[nf->type])*4;
if (prinst.fields_size < (nf->ofs+type_size[nf->type])*4)
prinst.fields_size = (nf->ofs+type_size[nf->type])*4;
prinst.numfields++;
}
fld16[i].s_name += stringadjust;
}
if (reorg && !(progfuncs->funcs.fieldadjust && !pr_typecurrent))
if (reorg && !(progfuncs->funcs.fieldadjust && !prinst.pr_typecurrent))
for (i=0 ; i<pr_progs->numfielddefs ; i++)
{
if (pr_types)
@ -3136,14 +3136,14 @@ retry:
type = pr_types[pr_fielddefs32[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL)].type;
else
type = pr_fielddefs32[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL);
if (progfuncs->funcs.fieldadjust && !pr_typecurrent) //we need to make sure all fields appear in their original place.
if (progfuncs->funcs.fieldadjust && !prinst.pr_typecurrent) //we need to make sure all fields appear in their original place.
QC_RegisterFieldVar(&progfuncs->funcs, type, pr_fielddefs32[i].s_name+pr_strings, 4*(pr_fielddefs32[i].ofs+progfuncs->funcs.fieldadjust), -1);
else if (type == ev_vector)
QC_RegisterFieldVar(&progfuncs->funcs, type, pr_fielddefs32[i].s_name+pr_strings, -1, pr_fielddefs32[i].ofs);
}
pr_fielddefs32[i].s_name += stringadjust;
}
if (reorg && !(progfuncs->funcs.fieldadjust && !pr_typecurrent))
if (reorg && !(progfuncs->funcs.fieldadjust && !prinst.pr_typecurrent))
for (i=0 ; i<pr_progs->numfielddefs ; i++)
{
if (pr_types)
@ -3234,8 +3234,8 @@ retry:
// QC_StartShares(progfuncs);
isfriked = true;
if (!pr_typecurrent) //progs 0 always acts as string stripped.
isfriked = -1; //partly to avoid some bad progs.
if (!prinst.pr_typecurrent) //progs 0 always acts as string stripped.
isfriked = -1; //partly to avoid some bad/optimised progs.
// len = 0;
switch(current_progstate->structtype)
@ -3344,7 +3344,7 @@ retry:
Sys_Error("Bad struct type");
}
if ((isfriked && pr_typecurrent)) //friked progs only allow one file.
if ((isfriked && prinst.pr_typecurrent)) //friked progs only allow one file.
{
printf("You are trying to load a string-stripped progs as an addon.\nThis behaviour is not supported. Try removing some optimizations.");
PRHunkFree(progfuncs, hmark);
@ -3442,7 +3442,7 @@ retry:
struct edict_s *PDECL QC_EDICT_NUM(pubprogfuncs_t *ppf, unsigned int n)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if (n >= maxedicts)
if (n >= prinst.maxedicts)
Sys_Error ("QCLIB: EDICT_NUM: bad number %i", n);
return prinst.edicttable[n];
@ -3452,7 +3452,7 @@ unsigned int PDECL QC_NUM_FOR_EDICT(pubprogfuncs_t *ppf, struct edict_s *e)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
edictrun_t *er = (edictrun_t*)e;
if (er->entnum >= maxedicts)
if (!er || er->entnum >= prinst.maxedicts)
Sys_Error ("QCLIB: NUM_FOR_EDICT: bad pointer (%p)", e);
return er->entnum;
}

View File

@ -356,19 +356,21 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf, int showlocals)
//locals:1 = top only
//locals:2 = ALL locals.
if ((i == pr_depth && showlocals == 1) || showlocals >= 2)
for (arg = 0; arg < f->locals; arg++)
{
ddef16_t *local;
local = ED_GlobalAtOfs16(progfuncs, f->parm_start+arg);
if (!local)
for (arg = 0; arg < f->locals; arg++)
{
//printf(" ofs %i: %f : %i\n", f->parm_start+arg, *(float *)(globalbase - f->locals+arg), *(int *)(globalbase - f->locals+arg) );
}
else
{
printf(" %s: %s\n", local->s_name+progfuncs->funcs.stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase+arg), false));
if (local->type == ev_vector)
arg+=2;
ddef16_t *local;
local = ED_GlobalAtOfs16(progfuncs, f->parm_start+arg);
if (!local)
{
//printf(" ofs %i: %f : %i\n", f->parm_start+arg, *(float *)(globalbase - f->locals+arg), *(int *)(globalbase - f->locals+arg) );
}
else
{
printf(" %s: %s\n", local->s_name+progfuncs->funcs.stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase+arg), false));
if (local->type == ev_vector)
arg+=2;
}
}
}
if (i == pr_depth)
@ -377,7 +379,7 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf, int showlocals)
}
if (i == pr_depth)
globalbase = localstack + localstack_used;
globalbase = prinst.localstack + prinst.localstack_used;
}
}
progfuncs->funcs.debug_trace = tracing;
@ -405,7 +407,7 @@ int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int progsn
pr_stack[pr_depth].s = pr_xstatement;
pr_stack[pr_depth].f = pr_xfunction;
pr_stack[pr_depth].progsnum = progsnum;
pr_stack[pr_depth].pushed = pr_spushed;
pr_stack[pr_depth].pushed = prinst.spushed;
pr_stack[pr_depth].stepping = progfuncs->funcs.debug_trace;
if (progfuncs->funcs.debug_trace == DEBUG_TRACE_OVER)
progfuncs->funcs.debug_trace = DEBUG_TRACE_OFF;
@ -427,20 +429,20 @@ int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int progsn
return pr_xstatement;
}
localstack_used += pr_spushed; //make sure the call doesn't hurt pushed pointers
prinst.localstack_used += prinst.spushed; //make sure the call doesn't hurt pushed pointers
// save off any locals that the new function steps on (to a side place, fromwhere they are restored on exit)
c = f->locals;
if (localstack_used + c > LOCALSTACK_SIZE)
if (prinst.localstack_used + c > LOCALSTACK_SIZE)
{
localstack_used -= pr_spushed;
prinst.localstack_used -= prinst.spushed;
pr_depth--;
PR_RunError (&progfuncs->funcs, "PR_ExecuteProgram: locals stack overflow\n");
}
for (i=0 ; i < c ; i++)
localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];
localstack_used += c;
prinst.localstack[prinst.localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];
prinst.localstack_used += c;
// copy parameters (set initial values)
o = f->parm_start;
@ -471,18 +473,18 @@ int ASMCALL PR_LeaveFunction (progfuncs_t *progfuncs)
// restore locals from the stack
c = pr_xfunction->locals;
localstack_used -= c;
if (localstack_used < 0)
prinst.localstack_used -= c;
if (prinst.localstack_used < 0)
PR_RunError (&progfuncs->funcs, "PR_ExecuteProgram: locals stack underflow\n");
for (i=0 ; i < c ; i++)
((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i];
((int *)pr_globals)[pr_xfunction->parm_start + i] = prinst.localstack[prinst.localstack_used+i];
// up stack
pr_depth--;
PR_SwitchProgsParms(progfuncs, pr_stack[pr_depth].progsnum);
pr_spushed = pr_stack[pr_depth].pushed;
prinst.spushed = pr_stack[pr_depth].pushed;
if (!progfuncs->funcs.debug_trace)
progfuncs->funcs.debug_trace = pr_stack[pr_depth].stepping;
@ -499,7 +501,7 @@ int ASMCALL PR_LeaveFunction (progfuncs_t *progfuncs)
else
pr_xfunction = pr_stack[pr_depth].f;
localstack_used -= pr_spushed;
prinst.localstack_used -= prinst.spushed;
return pr_stack[pr_depth].s;
}
@ -510,10 +512,10 @@ ddef32_t *ED_FindLocalOrGlobal(progfuncs_t *progfuncs, char *name, eval_t **val)
ddef16_t *def16;
int i;
if (pr_typecurrent < 0)
if (prinst.pr_typecurrent < 0)
return NULL;
switch (pr_progstate[pr_typecurrent].structtype)
switch (pr_progstate[prinst.pr_typecurrent].structtype)
{
case PST_DEFAULT:
case PST_KKQWSV:
@ -526,7 +528,7 @@ ddef32_t *ED_FindLocalOrGlobal(progfuncs_t *progfuncs, char *name, eval_t **val)
continue;
if (!strcmp(def16->s_name+progfuncs->funcs.stringtable, name))
{
*val = (eval_t *)&pr_progstate[pr_typecurrent].globals[pr_xfunction->parm_start+i];
*val = (eval_t *)&pr_progstate[prinst.pr_typecurrent].globals[pr_xfunction->parm_start+i];
//we need something like this for functions that are not the top layer
// *val = (eval_t *)&localstack[localstack_used-pr_xfunction->numparms*4];
@ -555,7 +557,7 @@ ddef32_t *ED_FindLocalOrGlobal(progfuncs_t *progfuncs, char *name, eval_t **val)
continue;
if (!strcmp(def32->s_name+progfuncs->funcs.stringtable, name))
{
*val = (eval_t *)&pr_progstate[pr_typecurrent].globals[pr_xfunction->parm_start+i];
*val = (eval_t *)&pr_progstate[prinst.pr_typecurrent].globals[pr_xfunction->parm_start+i];
//we need something like this for functions that are not the top layer
// *val = (eval_t *)&localstack[localstack_used-pr_xfunction->numparms*4];
@ -571,7 +573,7 @@ ddef32_t *ED_FindLocalOrGlobal(progfuncs_t *progfuncs, char *name, eval_t **val)
def32 = NULL;
}
*val = (eval_t *)&pr_progstate[pr_typecurrent].globals[def32->ofs];
*val = (eval_t *)&pr_progstate[prinst.pr_typecurrent].globals[def32->ofs];
return &def;
}
@ -672,7 +674,7 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, char *key, eval_t **result, etype_
ed = PROG_TO_EDICT(progfuncs, val->_int);
if (!ed)
return false;
if (fofs < 0 || fofs >= (int)max_fields_size)
if (fofs < 0 || fofs >= (int)prinst.max_fields_size)
return false;
val = (eval_t *) (((char *)ed->fields) + fofs*4);
}
@ -908,7 +910,7 @@ char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key)
//int EditorHighlightLine(window_t *wnd, int line);
void SetExecutionToLine(progfuncs_t *progfuncs, int linenum)
{
int pn = pr_typecurrent;
int pn = prinst.pr_typecurrent;
int snum;
const mfunction_t *f = pr_xfunction;
@ -945,11 +947,11 @@ int PDECL PR_ToggleBreakpoint(pubprogfuncs_t *ppf, char *filename, int linenum,
int ret=0;
unsigned int fl;
unsigned int i;
int pn = pr_typecurrent;
int pn = prinst.pr_typecurrent;
mfunction_t *f;
int op = 0; //warning about not being initialized before use
for (pn = 0; (unsigned)pn < maxprogs; pn++)
for (pn = 0; (unsigned)pn < prinst.maxprogs; pn++)
{
if (!pr_progstate || !pr_progstate[pn].progs)
continue;
@ -1119,7 +1121,7 @@ static int lastline = 0;
static int ignorestatement = 0; //
static const char *lastfile = 0;
int pn = pr_typecurrent;
int pn = prinst.pr_typecurrent;
int i;
const mfunction_t *f = pr_xfunction;
int faultline;
@ -1202,6 +1204,13 @@ static const char *lastfile = 0;
continue;
else if(debugaction == DEBUG_TRACE_ABORT)
progfuncs->funcs.parms->Abort ("Debugging terminated");
else if (debugaction == DEBUG_TRACE_OFF)
{
//if we're resuming, don't hit any lingering step-over triggers
progfuncs->funcs.debug_trace = DEBUG_TRACE_OFF;
for (i = 0; i < pr_depth; i++)
pr_stack[pr_depth-1].stepping = DEBUG_TRACE_OFF;
}
else if (debugaction == DEBUG_TRACE_OUT)
{
//clear tracing for now, but ensure that it'll be reactivated once we reach the caller (if from qc)
@ -1314,7 +1323,7 @@ pbool PR_RunWarning (pubprogfuncs_t *ppf, char *error, ...)
const char *PR_GetEdictClassname(progfuncs_t *progfuncs, int edict)
{
fdef_t *cnfd = ED_FindField(progfuncs, "classname");
if (cnfd && edict < maxedicts)
if (cnfd && edict < prinst.maxedicts)
{
string_t *v = (string_t *)((char *)edvars(PROG_TO_EDICT(progfuncs, edict)) + cnfd->ofs*4);
return PR_StringToNative(&progfuncs->funcs, *v);
@ -1367,7 +1376,7 @@ static casecmprange_t casecmprange[] =
printf ("runaway loop error\n"); \
while(pr_depth > prinst.exitdepth) \
PR_LeaveFunction(progfuncs); \
pr_spushed = 0; \
prinst.spushed = 0; \
return -1; \
}
@ -1562,10 +1571,10 @@ void PDECL PR_ExecuteProgram (pubprogfuncs_t *ppf, func_t fnum)
unsigned int newprogs = (fnum & 0xff000000)>>24;
initial_progs = pr_typecurrent;
initial_progs = prinst.pr_typecurrent;
if (newprogs != initial_progs)
{
if (newprogs >= maxprogs || !&pr_progstate[newprogs].globals) //can happen with hexen2...
if (newprogs >= prinst.maxprogs || !&pr_progstate[newprogs].globals) //can happen with hexen2...
{
printf("PR_ExecuteProgram: tried branching into invalid progs\n");
return;
@ -1701,7 +1710,7 @@ struct qcthread_s *PDECL PR_ForkStack(pubprogfuncs_t *ppf)
for (l = 0; l < f->locals; l++)
{
thread->lstack[localsoffset-baselocalsoffset + l ] = ((int *)pr_globals)[f->parm_start + l];
((int *)pr_globals)[f->parm_start + l] = localstack[localsoffset+l]; //copy the old value into the globals (so the older functions have the correct locals.
((int *)pr_globals)[f->parm_start + l] = prinst.localstack[localsoffset+l]; //copy the old value into the globals (so the older functions have the correct locals.
}
}
@ -1721,8 +1730,8 @@ struct qcthread_s *PDECL PR_ForkStack(pubprogfuncs_t *ppf)
thread->lstackused = localsoffset - baselocalsoffset;
thread->xstatement = pr_xstatement;
thread->xfunction = pr_xfunction - pr_progstate[pr_typecurrent].functions;
thread->xprogs = pr_typecurrent;
thread->xfunction = pr_xfunction - pr_progstate[prinst.pr_typecurrent].functions;
thread->xprogs = prinst.pr_typecurrent;
return thread;
}
@ -1743,7 +1752,7 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
progsnum_t prnum = thread->xprogs;
int fnum = thread->xfunction;
if (localstack_used + thread->lstackused > LOCALSTACK_SIZE)
if (prinst.localstack_used + thread->lstackused > LOCALSTACK_SIZE)
PR_RunError(&progfuncs->funcs, "Too many locals on resumtion of QC thread\n");
if (pr_depth + thread->fstackdepth > MAX_STACK_DEPTH)
@ -1751,7 +1760,7 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
//do progs switching stuff as appropriate. (fteqw only)
initial_progs = pr_typecurrent;
initial_progs = prinst.pr_typecurrent;
PR_SwitchProgsParms(progfuncs, prnum);
@ -1781,7 +1790,7 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
f = pr_progstate[thread->fstack[i+1].progsnum].functions + thread->fstack[i+1].fnum;
for (l = 0; l < f->locals; l++)
{
localstack[localstack_used++] = ((int *)pr_globals)[f->parm_start + l];
prinst.localstack[prinst.localstack_used++] = ((int *)pr_globals)[f->parm_start + l];
((int *)pr_globals)[f->parm_start + l] = thread->lstack[ls++];
}
@ -1797,8 +1806,8 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
// thread->lstackused -= f->locals; //the current function is the odd one out.
//add on the locals stack
memcpy(localstack+localstack_used, thread->lstack, sizeof(int)*thread->lstackused);
localstack_used += thread->lstackused;
memcpy(prinst.localstack+prinst.localstack_used, thread->lstack, sizeof(int)*thread->lstackused);
prinst.localstack_used += thread->lstackused;
//bung the locals of the current function on the stack.
// for (i=0 ; i < f->locals ; i++)

View File

@ -19,11 +19,11 @@ int maxshares;
//switches progs without preserving parms/ret/shared
pbool PR_SwitchProgs(progfuncs_t *progfuncs, progsnum_t type)
{
if ((unsigned)type >= maxprogs)
if ((unsigned)type >= prinst.maxprogs)
{
if (type == -1)
{
pr_typecurrent = -1;
prinst.pr_typecurrent = -1;
current_progstate = NULL;
return true;
}
@ -36,7 +36,7 @@ pbool PR_SwitchProgs(progfuncs_t *progfuncs, progsnum_t type)
current_progstate = &pr_progstate[(unsigned)type];
pr_typecurrent = type;
prinst.pr_typecurrent = type;
return true;
}
@ -47,7 +47,7 @@ pbool PR_SwitchProgsParms(progfuncs_t *progfuncs, progsnum_t newpr) //from 2 to
unsigned int a;
progstate_t *np;
progstate_t *op;
int oldpr = pr_typecurrent;
int oldpr = prinst.pr_typecurrent;
if (newpr == oldpr)
{
@ -58,12 +58,12 @@ pbool PR_SwitchProgsParms(progfuncs_t *progfuncs, progsnum_t newpr) //from 2 to
np = &pr_progstate[(int)newpr];
op = &pr_progstate[(int)oldpr];
if ((unsigned)newpr >= maxprogs || !np->globals)
if ((unsigned)newpr >= prinst.maxprogs || !np->globals)
{
printf("QCLIB: Bad prog type - %i", newpr);
return false;
}
if ((unsigned)oldpr >= maxprogs || !op->globals) //startup?
if ((unsigned)oldpr >= prinst.maxprogs || !op->globals) //startup?
return PR_SwitchProgs(progfuncs, newpr);
//copy parms.
@ -78,9 +78,9 @@ pbool PR_SwitchProgsParms(progfuncs_t *progfuncs, progsnum_t newpr) //from 2 to
np->globals[OFS_RETURN+2] = op->globals[OFS_RETURN+2];
//move the vars defined as shared.
for (a = 0; a < numshares; a++)//fixme: make offset per progs
for (a = 0; a < prinst.numshares; a++)//fixme: make offset per progs
{
memmove(&((int *)np->globals)[shares[a].varofs], &((int *)op->globals)[shares[a].varofs], shares[a].size*4);
memmove(&((int *)np->globals)[prinst.shares[a].varofs], &((int *)op->globals)[prinst.shares[a].varofs], prinst.shares[a].size*4);
/* ((int *)p1->globals)[shares[a].varofs] = ((int *)p2->globals)[shares[a].varofs];
if (shares[a].size > 1)
{
@ -98,12 +98,12 @@ progsnum_t PDECL PR_LoadProgs(pubprogfuncs_t *ppf, const char *s)
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
unsigned int a;
progsnum_t oldtype;
oldtype = pr_typecurrent;
for (a = 0; a < maxprogs; a++)
oldtype = prinst.pr_typecurrent;
for (a = 0; a < prinst.maxprogs; a++)
{
if (pr_progstate[a].progs == NULL)
{
pr_typecurrent = a;
prinst.pr_typecurrent = a;
current_progstate = &pr_progstate[a];
if (PR_ReallyLoadProgs(progfuncs, s, &pr_progstate[a], false)) //try and load it
{
@ -136,7 +136,7 @@ void PR_ShiftParms(progfuncs_t *progfuncs, int amount)
void PR_Clear(progfuncs_t *progfuncs)
{
unsigned int a;
for (a = 0; a < maxprogs; a++)
for (a = 0; a < prinst.maxprogs; a++)
{
#ifdef QCJIT
if (pr_progstate[a].jit)
@ -150,11 +150,11 @@ void PR_Clear(progfuncs_t *progfuncs)
void QC_StartShares(progfuncs_t *progfuncs)
{
numshares = 0;
maxshares = 32;
if (shares)
externs->memfree(shares);
shares = externs->memalloc(sizeof(sharedvar_t)*maxshares);
prinst.numshares = 0;
prinst.maxshares = 32;
if (prinst.shares)
externs->memfree(prinst.shares);
prinst.shares = externs->memalloc(sizeof(sharedvar_t)*prinst.maxshares);
}
void PDECL QC_AddSharedVar(pubprogfuncs_t *ppf, int start, int size) //fixme: make offset per progs and optional
{
@ -162,33 +162,33 @@ void PDECL QC_AddSharedVar(pubprogfuncs_t *ppf, int start, int size) //fixme: ma
int ofs;
unsigned int a;
if (numshares >= maxshares)
if (prinst.numshares >= prinst.maxshares)
{
void *buf;
buf = shares;
maxshares += 16;
shares = externs->memalloc(sizeof(sharedvar_t)*maxshares);
buf = prinst.shares;
prinst.maxshares += 16;
prinst.shares = externs->memalloc(sizeof(sharedvar_t)*prinst.maxshares);
memcpy(shares, buf, sizeof(sharedvar_t)*numshares);
memcpy(prinst.shares, buf, sizeof(sharedvar_t)*prinst.numshares);
externs->memfree(buf);
}
ofs = start;
for (a = 0; a < numshares; a++)
for (a = 0; a < prinst.numshares; a++)
{
if (shares[a].varofs+shares[a].size == ofs)
if (prinst.shares[a].varofs+prinst.shares[a].size == ofs)
{
shares[a].size += size; //expand size.
prinst.shares[a].size += size; //expand size.
return;
}
if (shares[a].varofs == start)
if (prinst.shares[a].varofs == start)
return;
}
shares[numshares].varofs = start;
shares[numshares].size = size;
numshares++;
prinst.shares[prinst.numshares].varofs = start;
prinst.shares[prinst.numshares].size = size;
prinst.numshares++;
}
@ -240,9 +240,9 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name
if (!name) //engine can use this to offset all progs fields
{ //which fixes constant field offsets (some ktpro arrays)
progfuncs->funcs.fieldadjust = fields_size/4;
progfuncs->funcs.fieldadjust = prinst.fields_size/4;
#ifdef MAPPING_DEBUG
printf("FIELD ADJUST: %i %i %i\n", progfuncs->funcs.fieldadjust, fields_size, (int)fields_size/4);
printf("FIELD ADJUST: %i %i %i\n", progfuncs->funcs.fieldadjust, prinst.fields_size, (int)prinst.fields_size/4);
#endif
return 0;
}
@ -322,7 +322,7 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name
}
else
{ //we just found a new fieldname inside a progs
prinst.field[fnum].ofs = ofs = fields_size/4; //add on the end
prinst.field[fnum].ofs = ofs = prinst.fields_size/4; //add on the end
//if the progs field offset matches annother offset in the same progs, make it match up with the earlier one.
if (progsofs>=0)
@ -361,10 +361,10 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name
}
}
// if (type != ev_vector)
if (fields_size < (ofs+type_size[type])*4)
fields_size = (ofs+type_size[type])*4;
if (prinst.fields_size < (ofs+type_size[type])*4)
prinst.fields_size = (ofs+type_size[type])*4;
if (max_fields_size && fields_size > max_fields_size)
if (prinst.max_fields_size && prinst.fields_size > prinst.max_fields_size)
Sys_Error("Allocated too many additional fields after ents were inited.");
#ifdef MAPPING_DEBUG

View File

@ -68,6 +68,7 @@ typedef struct
unsigned long long timestamp;
} prstack_t;
//FIXME: the defines hidden inside this structure are evil.
typedef struct prinst_s
{
char **tempstrings;
@ -86,10 +87,8 @@ typedef struct prinst_s
struct progstate_s * progstate;
#define pr_progstate prinst.progstate
progsnum_t pr_typecurrent;
#define pr_typecurrent prinst.pr_typecurrent
progsnum_t pr_typecurrent; //active index into progstate array. fixme: remove in favour of only using current_progstate
unsigned int maxprogs;
#define maxprogs prinst.maxprogs
struct progstate_s *current_progstate;
#define current_progstate prinst.current_progstate
@ -100,20 +99,16 @@ typedef struct prinst_s
etype_t watch_type;
unsigned int numshares;
#define numshares prinst.numshares
sharedvar_t *shares; //shared globals, not including parms
#define shares prinst.shares
unsigned int maxshares;
#define maxshares prinst.maxshares
struct prmemb_s *memblocks;
#define memb prinst.memblocks
unsigned int maxfields;
unsigned int numfields;
fdef_t *field; //biggest size
int reorganisefields;
int reorganisefields;
//pr_exec.c
@ -123,13 +118,10 @@ int reorganisefields;
int pr_depth;
#define pr_depth prinst.pr_depth
int spushed;
#define pr_spushed prinst.spushed
#define LOCALSTACK_SIZE 4096
int localstack[LOCALSTACK_SIZE];
#define localstack prinst.localstack
int localstack_used;
#define localstack_used prinst.localstack_used
int debugstatement;
int continuestatement;
@ -144,18 +136,10 @@ int reorganisefields;
//pr_edict.c
unsigned int maxedicts;
#define maxedicts prinst.maxedicts
evalc_t spawnflagscache;
#define spawnflagscache prinst.spawnflagscache
unsigned int fields_size; // in bytes
#define fields_size prinst.fields_size
unsigned int max_fields_size;
#define max_fields_size prinst.max_fields_size
//initlib.c

View File

@ -53,7 +53,14 @@ typedef struct {
} evalc_t;
#define sizeofevalc sizeof(evalc_t)
typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_variant, ev_struct, ev_union, ev_accessor} etype_t;
enum {DEBUG_TRACE_OFF, DEBUG_TRACE_INTO, DEBUG_TRACE_OVER, DEBUG_TRACE_UNBREAK, DEBUG_TRACE_OUT, DEBUG_TRACE_ABORT, DEBUG_TRACE_NORESUME};
enum {
DEBUG_TRACE_OFF, //debugging should be off.
DEBUG_TRACE_INTO, //debug into functions
DEBUG_TRACE_OVER, //switch debugging off while executing child functions (and back on afterwards)
DEBUG_TRACE_OUT, //keep running until the end of the current function (trigger single-stepping again at that point)
DEBUG_TRACE_ABORT, //give up with an endgame.
DEBUG_TRACE_NORESUME //line number or something changed, but we should still be sitting at the debugger.
};
typedef struct fdef_s
{

View File

@ -320,6 +320,7 @@ struct QCC_typeparam_s
{
struct QCC_type_s *type;
pbool optional;
pbool out;
unsigned int ofs;
unsigned int arraysize;
char *paramname;
@ -531,6 +532,7 @@ extern pbool keyword_break;
extern pbool keyword_case;
extern pbool keyword_class;
extern pbool keyword_const;
extern pbool keyword_inout;
extern pbool keyword_optional;
extern pbool keyword_continue;
extern pbool keyword_default;

View File

@ -36,6 +36,7 @@ pbool keyword_until; //hexen2
pbool keyword_thinktime;//hexen2
pbool keyword_asm;
pbool keyword_class;
pbool keyword_inout;
pbool keyword_optional;
pbool keyword_const; //fixme
pbool keyword_entity; //for skipping the local
@ -632,10 +633,12 @@ QCC_opcode_t pr_opcodes[] =
{7, "&~", "BITCLR_I", 6, ASSOC_LEFT, &type_integer, &type_integer, &type_integer},
{7, "+", "ADD_SI", 4, ASSOC_LEFT, &type_string, &type_integer, &type_string},
{7, "+", "ADD_IS", 7, ASSOC_LEFT, &type_integer, &type_string, &type_string},
{7, "+", "ADD_PF", 6, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer},
{7, "+", "ADD_FP", 6, ASSOC_LEFT, &type_float, &type_pointer, &type_pointer},
{7, "+", "ADD_PI", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer},
{7, "+", "ADD_IP", 6, ASSOC_LEFT, &type_integer, &type_pointer, &type_pointer},
{7, "-", "SUB_SI", 7, ASSOC_LEFT, &type_string, &type_integer, &type_string},
{7, "-", "SUB_PF", 6, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer},
{7, "-", "SUB_PI", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer},
{7, "-", "SUB_PP", 6, ASSOC_LEFT, &type_pointer, &type_pointer, &type_integer},
@ -732,6 +735,12 @@ QCC_opcode_t *opcodes_addstore[] =
&pr_opcodes[OP_ADD_FI],
&pr_opcodes[OP_ADD_IF],
&pr_opcodes[OP_ADD_SF],
&pr_opcodes[OP_ADD_PI],
&pr_opcodes[OP_ADD_IP],
&pr_opcodes[OP_ADD_PF],
&pr_opcodes[OP_ADD_FP],
&pr_opcodes[OP_ADD_SI],
&pr_opcodes[OP_ADD_IS],
NULL
};
QCC_opcode_t *opcodes_substore[] =
@ -752,6 +761,10 @@ QCC_opcode_t *opcodes_substore[] =
&pr_opcodes[OP_SUB_FI],
&pr_opcodes[OP_SUB_IF],
&pr_opcodes[OP_SUB_S],
&pr_opcodes[OP_SUB_PP],
&pr_opcodes[OP_SUB_PI],
&pr_opcodes[OP_SUB_PF],
&pr_opcodes[OP_SUB_SI],
NULL
};
QCC_opcode_t *opcodes_mulstore[] =
@ -900,11 +913,12 @@ QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] =
&pr_opcodes[OP_BITOR_FI],
&pr_opcodes[OP_BITXOR_I],
&pr_opcodes[OP_RSHIFT_I],
&pr_opcodes[OP_LSHIFT_I],
&pr_opcodes[OP_BITXOR_F],
&pr_opcodes[OP_RSHIFT_I],
&pr_opcodes[OP_RSHIFT_F],
&pr_opcodes[OP_LSHIFT_I],
&pr_opcodes[OP_LSHIFT_F],
&pr_opcodes[OP_MOD_F],
@ -1339,7 +1353,11 @@ pbool QCC_StatementIsAJump(int stnum, int notifdest);
const char *QCC_GetSRefName(QCC_sref_t ref)
{
if (ref.sym && ref.sym->name && !ref.ofs)
{
if (ref.sym->temp)
return ref.cast->name;
return ref.sym->name;
}
return "TEMP";
}
@ -1504,7 +1522,7 @@ static void QCC_ClobberDef(QCC_def_t *def)
a->nextlocal = NULL;
if (a->refcount)
{
tmp = QCC_GetTemp(a->type);
tmp = QCC_GetTemp(a->type->type==ev_variant?type_vector:a->type);
for (st = a->fromstatement; st < numstatements; st++)
{
if (statements[st].a.sym == a)
@ -1522,7 +1540,7 @@ static void QCC_ClobberDef(QCC_def_t *def)
a->ofs = tmp.sym->ofs;
tmp.sym = a;
tmp.sym->refcount = a->refcount;
if (a->type->type == ev_vector)
if (a->type->type==ev_variant || a->type->type == ev_vector)
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_V], from, tmp, NULL, STFL_PRESERVEB));
else
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], from, tmp, NULL, STFL_PRESERVEB));
@ -1830,7 +1848,7 @@ static void QCC_fprintfLocals(FILE *f, QCC_def_t *locals)
{
if (!tempsinfo[u].locked)
{
fprintf(f, "local %s temp_%i;\n", (tempsinfo[u].size == 1)?"float":"vector", u);
fprintf(f, "local %s temp_%u;\n", (tempsinfo[u].size == 1)?"float":"vector", (unsigned)u);
}
}
}
@ -2805,43 +2823,64 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
}
else
{
QCC_PR_ParseWarning(0, "string(string,float) AddStringFloat: emulation depends upon denormals");
QCC_PR_ParseWarning(0, "OP_ADD_SI: string+float may be unsafe");
var_b = QCC_SupplyConversion(var_b, ev_integer, true); //FIXME: this should be an unconditional float->int conversion
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], var_a, var_b, NULL, 0);
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], var_a, var_b, NULL, 0);
}
var_c.cast = type_string;
return var_c;
case OP_ADD_SI:
QCC_PR_ParseWarning(0, "OP_ADD_SI: denormals may be unsafe");
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], var_a, var_b, NULL, 0);
case OP_ADD_IS:
QCC_PR_ParseWarning(0, "OP_ADD_SI: string+int may be unsafe");
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], var_a, var_b, NULL, 0);
var_c.cast = type_string;
return var_c;
case OP_ADD_PF:
case OP_ADD_FP:
case OP_ADD_PI:
case OP_ADD_IP:
var_c = (op == &pr_opcodes[OP_ADD_PF] || op == &pr_opcodes[OP_ADD_PI])?var_a:var_b;
var_b = (op == &pr_opcodes[OP_ADD_PF] || op == &pr_opcodes[OP_ADD_PI])?var_b:var_a;
if (op == &pr_opcodes[OP_ADD_FP] || op == &pr_opcodes[OP_ADD_PF])
var_b = QCC_SupplyConversion(var_b, ev_integer, true); //FIXME: this should be an unconditional float->int conversion
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_I], var_b, QCC_MakeIntConst(var_c.cast->size), NULL, 0);
return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_PIW], var_c, var_b, NULL, 0);
{
QCC_type_t *t;
var_c = (op == &pr_opcodes[OP_ADD_PF] || op == &pr_opcodes[OP_ADD_PI])?var_a:var_b;
t = var_c.cast;
var_b = (op == &pr_opcodes[OP_ADD_PF] || op == &pr_opcodes[OP_ADD_PI])?var_b:var_a;
if (op == &pr_opcodes[OP_ADD_FP] || op == &pr_opcodes[OP_ADD_PF])
var_b = QCC_SupplyConversion(var_b, ev_integer, true); //FIXME: this should be an unconditional float->int conversion
if (var_c.cast->aux_type->type == ev_void) //void* is treated as a byte type.
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], var_c, var_b, NULL, 0);
else
{
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_I], var_b, QCC_MakeIntConst(var_c.cast->aux_type->size), NULL, 0);
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_PIW], var_c, var_b, NULL, 0);
}
var_c.cast = t;
}
return var_c;
case OP_SUB_PF:
case OP_SUB_PI:
var_c = var_a;
var_b = var_b;
if (op == &pr_opcodes[OP_SUB_PF])
var_b = QCC_SupplyConversion(var_b, ev_integer, true); //FIXME: this should be an unconditional float->int conversion
//fixme: word size
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_I], var_b, QCC_MakeIntConst(var_c.cast->size*4), NULL, 0);
return QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_c, var_b, NULL, 0);
if (var_c.cast->aux_type->type == ev_void) //void* is treated as a byte type.
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_c, var_b, NULL, 0);
else
{
//fixme: word size
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_I], var_b, QCC_MakeIntConst(var_c.cast->aux_type->size*4), NULL, 0);
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_c, var_b, NULL, 0);
}
var_c.cast = var_a.cast;
return var_c;
case OP_SUB_PP:
if (typecmp(var_a.cast, var_b.cast))
QCC_PR_ParseError(0, "incompatible pointer types");
//determine byte offset
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_a, var_b, NULL, 0);
if (var_a.cast->aux_type->type == ev_void)
return var_c; //we're done if we're using void/bytes
//determine divisor (fixme: word size)
var_b = QCC_MakeIntConst(var_c.cast->size*4);
var_b = QCC_MakeIntConst(var_a.cast->aux_type->size*4);
//divide the result
return QCC_PR_StatementFlags(&pr_opcodes[OP_DIV_I], var_c, var_b, NULL, 0);
@ -2983,9 +3022,12 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
var_c = QCC_PR_GetSRef(NULL, "itof", NULL, false, 0, 0);
if (!var_c.cast)
{
QCC_PR_ParseError(0, "itof function not defined: cannot emulate int -> float conversions");
//with denormals, 5 * 1i -> 5i
QCC_PR_ParseWarning(0, "itof emulation: denormals have limited precision");
var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_DIV_F], var_a, QCC_MakeIntConst(1), NULL, 0);
}
var_a = QCC_PR_GenerateFunctionCall(nullsref, var_c, &var_a, &type_integer, 1);
else
var_a = QCC_PR_GenerateFunctionCall(nullsref, var_c, &var_a, &type_integer, 1);
var_a.cast = type_float;
}
if (var_b.cast)
@ -3024,17 +3066,18 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
}
}
return var_a;
case OP_STORE_P:
case OP_STORE_I:
op = pr_opcodes+OP_STORE_F;
break;
case OP_BITXOR_F:
// a = (a & ~b) | (b & ~a);
// r = (a & ~b) | (b & ~a);
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_F], var_b, nullsref, NULL, STFL_PRESERVEA);
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_F], var_a, var_c, NULL, STFL_PRESERVEA);
var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_F], var_a, nullsref, NULL, 0);
var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_F], var_b, var_a, NULL, 0);
return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_F], var_c, var_a, NULL, STFL_PRESERVEA);
return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_F], var_c, var_a, NULL, 0);
case OP_IF_S:
tmp = QCC_MakeFloatConst(0);
@ -3211,6 +3254,10 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
var_a = tmp;
break;
case OP_LOAD_P:
case OP_LOAD_I:
op = &pr_opcodes[OP_LOAD_F];
break;
case OP_STOREP_P:
op = &pr_opcodes[OP_STOREP_I];
break;
@ -3619,6 +3666,32 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
else
op = &pr_opcodes[OP_OR_F]; //generally works. if there's no other choice then meh.
break;
// case OP_LOADP_V:
// break;
case OP_LOADP_F:
case OP_LOADP_S:
case OP_LOADP_ENT:
case OP_LOADP_FLD:
case OP_LOADP_FNC:
case OP_LOADP_I:
{
QCC_type_t *argt[2] = {type_pointer, type_float};
QCC_sref_t fnc = QCC_PR_GetSRef(NULL, "memgetval", NULL, false, 0, 0);
QCC_sref_t arg[2];arg[0] = var_a;arg[1]=QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_b, nullsref, NULL, (flags&STFL_PRESERVEB)?STFL_PRESERVEA:0); //conversion return valuevar_b; //MSVC sucks when arg is a struct array. its fine when its a def_t ptr array
if (!fnc.cast)
QCC_PR_ParseError(0, "memgetval function not defined: cannot emulate OP_LOADP_*");
var_c = QCC_PR_GenerateFunctionCall(nullsref, fnc, arg, argt, 2);
var_c.cast = *op->type_c;
return var_c;
}
break;
case OP_ADD_PIW:
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_I], QCC_MakeIntConst(4), var_b, NULL, flags&STFL_PRESERVEB);
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], var_a, var_b, NULL, flags&~STFL_PRESERVEB);
var_c.cast = var_a.cast;
return var_c;
default:
{
int oldtarg = qcc_targetformat;
@ -3873,17 +3946,25 @@ void QCC_PrecacheSound (const char *n, int ch)
if (!*n)
return;
if (ch >= '1' && ch <= '9')
ch -= '0';
else
ch = 1;
for (i=0 ; i<numsounds ; i++)
if (!STRCMP(n, precache_sound[i].name))
{
if (!precache_sound[i].block || precache_sound[i].block > ch)
precache_sound[i].block = ch;
return;
}
if (numsounds == QCC_MAX_SOUNDS)
return;
// QCC_Error ("PrecacheSound: numsounds == MAX_SOUNDS");
strcpy (precache_sound[i].name, n);
if (ch >= '1' && ch <= '9')
precache_sound[i].block = ch - '0';
else
precache_sound[i].block = 1;
precache_sound[i].block = ch;
precache_sound[i].filename = strings+s_file;
precache_sound[i].fileline = pr_source_line;
numsounds++;
}
@ -3940,6 +4021,28 @@ void QCC_SetModel (const char *n)
precache_model[i].fileline = pr_source_line;
nummodels++;
}
void QCC_SoundUsed (const char *n)
{
int i;
if (!*n)
return;
for (i=0 ; i<numsounds ; i++)
if (!STRCMP(n, precache_sound[i].name))
{
precache_sound[i].used++;
return;
}
if (numsounds == QCC_MAX_SOUNDS)
return;
strcpy (precache_sound[i].name, n);
precache_sound[i].block = 0;
precache_sound[i].used=1;
precache_sound[i].filename = strings+s_file;
precache_sound[i].fileline = pr_source_line;
numsounds++;
}
void QCC_PrecacheTexture (const char *n, int ch)
{
@ -4502,6 +4605,19 @@ QCC_sref_t QCC_PR_GenerateFunctionCall (QCC_sref_t newself, QCC_sref_t func, QCC
QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(argcount), va_passcount, NULL, 0));
}
//free any references to ofs_ret if we know we're not going to make any calls that will clobber it.
if (callconvention == OP_CALL1H)
{
for (i = 0; i < argcount && i < 2; i++)
if (arglist[i].sym->generatedfor == &def_ret && arglist[i].sym->refcount == 1)
{
QCC_FreeTemp(arglist[i]);
arglist[i].sym = &def_ret;
QCC_ForceUnFreeDef(arglist[i].sym);
break;
}
}
QCC_ClobberDef(&def_ret);
/*can free temps used for arguments now*/
@ -4548,6 +4664,76 @@ QCC_sref_t QCC_PR_GenerateFunctionCall (QCC_sref_t newself, QCC_sref_t func, QCC
QCC_FreeTemp(oself);
QCC_FreeTemp(self);
if (func.cast->type == ev_function && func.cast->params)
{
for (i = 0; i < argcount && i < func.cast->num_parms; i++)
{
if (!func.cast->params[i].out)
continue;
if (arglist[i].sym->constant)
{
QCC_PR_ParseWarning(ERR_TYPEMISMATCHPARM, "Constant passed as out argument\n");
continue;
}
if (arglist[i].sym->temp)
{
QCC_PR_ParseWarning(ERR_TYPEMISMATCHPARM, "Temp passed as out argument\n");
continue;
}
if (i>=MAX_PARMS)
{
d = extra_parms[i - MAX_PARMS];
if (!d.cast)
{
char name[128];
QC_snprintfz(name, sizeof(name), "$parm%u", i);
d = extra_parms[i - MAX_PARMS] = QCC_PR_GetSRef(type_vector, name, NULL, true, 0, GDF_STRIP);
}
else
QCC_ForceUnFreeDef(d.sym);
}
else
{
d.sym = &def_parms[i];
d.ofs = 0;
d.cast = type_vector;
}
if (argtypelist && argtypelist[i])
d.cast = argtypelist[i];
else
d.cast = arglist[i].cast;
QCC_ForceUnFreeDef(arglist[i].sym);
//FIXME: if the def is a temp with only one reference, we can update the statement that generated the temp to directly store to the parm
if (d.cast->size == 3 || !opt_nonvec_parms)
QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_V], d, arglist[i], NULL, 0));
else
{
switch(d.cast->type)
{
case ev_entity:
QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_ENT], d, arglist[i], NULL, 0));
break;
case ev_string:
QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_S], d, arglist[i], NULL, 0));
break;
case ev_field:
QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_FLD], d, arglist[i], NULL, 0));
break;
case ev_function:
QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_FNC], d, arglist[i], NULL, 0));
break;
default:
QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], d, arglist[i], NULL, 0));
break;
}
optres_nonvec_parms++;
}
}
}
return retval;
}
@ -4623,7 +4809,8 @@ QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou
int oldstcount = numstatements;
#if 1
QCC_ref_t refbuf, *r;
r = QCC_PR_ParseRefValue(&refbuf, pr_classtype, false, false, false);
r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0);
// r = QCC_PR_ParseRefValue(&refbuf, pr_classtype, false, false, false);
if (r->type == REF_ARRAYHEAD && !r->index.cast)
{
e = r->base;
@ -4933,6 +5120,32 @@ QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou
return result;
}
else if (!strcmp(funcname, "used_sound"))
{
e = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
QCC_PR_Expect(")");
if (e.cast->type == ev_string && e.sym->constant && !e.sym->temp)
{
const char *value = &strings[e.sym->symboldata[e.ofs].string];
QCC_SoundUsed(value);
}
else
QCC_PR_ParseWarning(ERR_BADIMMEDIATETYPE, "Argument to used_sound intrinsic was not a string immediate.");
return e;
}
else if (!strcmp(funcname, "used_model"))
{
e = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
QCC_PR_Expect(")");
if (e.cast->type == ev_string && e.sym->constant && !e.sym->temp)
{
const char *value = &strings[e.sym->symboldata[e.ofs].string];
QCC_SetModel(value);
}
else
QCC_PR_ParseWarning(ERR_BADIMMEDIATETYPE, "Argument to used_model intrinsic was not a string immediate.");
return e;
}
else if (!strcmp(funcname, "autocvar") && !QCC_PR_CheckToken(")"))
{
char autocvarname[256];
@ -5153,6 +5366,11 @@ QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou
const char *value = &strings[e.sym->symboldata[e.ofs].string];
QCC_SetModel(value);
}
if (arg == 2 && !STRCMP(QCC_GetSRefName(func), "sound") && e.cast->type == ev_string && e.sym->constant && !e.sym->temp)
{
const char *value = &strings[e.sym->symboldata[e.ofs].string];
QCC_SoundUsed(value);
}
param[arg] = e;
paramtypes[arg] = p;
@ -5749,15 +5967,12 @@ static QCC_sref_t QCC_PR_ExpandField(QCC_sref_t ent, QCC_sref_t field, QCC_type_
break;
case ev_pointer:
r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_P], ent, field, NULL, preserveflags);
r.cast = fieldtype;
break;
case ev_field:
r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_FLD], ent, field, NULL, preserveflags);
r.cast = fieldtype;
break;
case ev_variant:
r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_FLD], ent, field, NULL, preserveflags);
r.cast = fieldtype;
break;
case ev_float:
r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_F], ent, field, NULL, preserveflags);
@ -5770,12 +5985,12 @@ static QCC_sref_t QCC_PR_ExpandField(QCC_sref_t ent, QCC_sref_t field, QCC_type_
break;
case ev_function:
r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_FNC], ent, field, NULL, preserveflags);
r.cast = fieldtype;
break;
case ev_entity:
r = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_ENT], ent, field, NULL, preserveflags);
break;
}
r.cast = fieldtype;
return r;
}
@ -5797,7 +6012,7 @@ static QCC_ref_t *QCC_PR_ParseField(QCC_ref_t *refbuf, QCC_ref_t *lhs)
}
else
field = QCC_PR_ParseRefValue(&fieldbuf, t, false, false, true);
if (field->cast->type == ev_field || field->cast->type == ev_variant)
if (field->type != REF_ARRAYHEAD && (field->cast->type == ev_field || field->cast->type == ev_variant))
{
//fields are generally always readonly. that refers to the field def itself, rather than products of said field.
//entities, like 'world' might also be consts. just ignore that fact. the def itself is not assigned, but the fields of said def.
@ -6324,6 +6539,8 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo
(!strcmp(name, "sizeof")) ||
(!strcmp(name, "entnum")) ||
(!strcmp(name, "autocvar")) ||
(!strcmp(name, "used_model")) ||
(!strcmp(name, "used_sound")) ||
(!strcmp(name, "va_arg")) ||
(!strcmp(name, "...")) || //for compat. otherwise wtf?
(!strcmp(name, "_")) ) //intrinsics, any old function with no args will do.
@ -6427,7 +6644,14 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo
else
t = QCC_PR_GetSRef(NULL, "self", NULL, true, 0, false);
d = QCC_PR_ParseArrayPointer(d, allowarrayassign, makearraypointers); //opportunistic vecmember[0] handling
if (d.sym->arraysize)
{
QCC_DefToRef(refbuf, d);
refbuf->type = REF_ARRAYHEAD;
d = QCC_RefToDef(QCC_PR_ParseRefArrayPointer(refbuf, refbuf, allowarrayassign, makearraypointers), true);
}
else
d = QCC_PR_ParseArrayPointer(d, allowarrayassign, makearraypointers); //opportunistic vecmember[0] handling
//then return a reference to this.field
QCC_PR_BuildRef(refbuf, REF_FIELD, t, d, d.cast->aux_type, false);
@ -6974,6 +7198,22 @@ void QCC_StoreToPointer(QCC_sref_t dest, QCC_sref_t source, QCC_type_t *type)
{
default:
QCC_PR_ParseErrorPrintSRef(ERR_INTERNAL, dest, "QCC_StoreToPointer doesn't know how to store to that type");
case ev_struct:
case ev_union:
{
int i;
for (i = 0; i+2 < type->size; i+=3)
{
QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_V], source, dest, QCC_MakeIntConst(i), false);
source.ofs += 3;
}
for (i = 0; i < type->size; i++)
{
QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_F], source, dest, QCC_MakeIntConst(i), false);
source.ofs += 1;
}
}
break;
case ev_float:
QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_F], source, dest, nullsref, false);
break;
@ -6993,7 +7233,10 @@ void QCC_StoreToPointer(QCC_sref_t dest, QCC_sref_t source, QCC_type_t *type)
QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_FLD], source, dest, nullsref, false);
break;
case ev_integer:
QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_I], source, dest, nullsref, false);
if (!QCC_OPCodeValid(&pr_opcodes[OP_STOREP_I]))
QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_FLD], source, dest, nullsref, false);
else
QCC_PR_SimpleStatement(&pr_opcodes[OP_STOREP_I], source, dest, nullsref, false);
break;
case ev_pointer:
if (!QCC_OPCodeValid(&pr_opcodes[OP_STOREP_P]))
@ -7003,44 +7246,35 @@ void QCC_StoreToPointer(QCC_sref_t dest, QCC_sref_t source, QCC_type_t *type)
break;
}
}
void QCC_LoadFromPointer(QCC_sref_t dest, QCC_sref_t source, QCC_sref_t idx, QCC_type_t *type)
QCC_sref_t QCC_LoadFromPointer(QCC_sref_t source, QCC_sref_t idx, QCC_type_t *type)
{
QCC_sref_t ret;
int op;
while (type->type == ev_accessor)
type = type->parentclass;
//fixme: we should probably handle entire structs or something
switch(type->type)
{
case ev_float:
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_F], source, idx, dest, false);
break;
case ev_string:
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_S], source, idx, dest, false);
break;
case ev_vector:
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_V], source, idx, dest, false);
break;
case ev_entity:
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_ENT], source, idx, dest, false);
break;
case ev_field:
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_FLD], source, idx, dest, false);
break;
case ev_function:
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_FNC], source, idx, dest, false);
break;
case ev_integer:
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_I], source, idx, dest, false);
break;
case ev_float: op = OP_LOADP_F; break;
case ev_string: op = OP_LOADP_S; break;
case ev_vector: op = OP_LOADP_V; break;
case ev_entity: op = OP_LOADP_ENT; break;
case ev_field: op = OP_LOADP_FLD; break;
case ev_function: op = OP_LOADP_FNC; break;
case ev_integer: op = OP_LOADP_I; break;
default:
QCC_PR_ParseErrorPrintSRef(ERR_INTERNAL, dest, "QCC_LoadFromPointer doesn't know how to load from that type");
QCC_PR_ParseError(ERR_INTERNAL, "QCC_LoadFromPointer doesn't know how to load from that type");
case ev_pointer:
if (!QCC_OPCodeValid(&pr_opcodes[OP_LOADP_P]))
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_I], source, idx, dest, false);
else
QCC_PR_SimpleStatement (&pr_opcodes[OP_LOADP_P], source, idx, dest, false);
op = OP_LOADP_P;
if (!QCC_OPCodeValid(&pr_opcodes[op]))
op = OP_LOADP_I;
break;
}
ret = QCC_PR_StatementFlags(&pr_opcodes[op], source, idx, NULL, STFL_PRESERVEA|STFL_PRESERVEB); //get pointer to precise def.
ret.cast = type;
return ret;
}
void QCC_StoreToArray(QCC_sref_t base, QCC_sref_t index, QCC_sref_t source, QCC_type_t *t)
{
@ -7413,7 +7647,6 @@ QCC_sref_t QCC_RefToDef(QCC_ref_t *ref, pbool freetemps)
QCC_UnFreeTemp(ret);
break;
case REF_POINTER:
tmp = QCC_GetTemp(ref->cast);
if (ref->index.cast)
{
// if (!freetemps)
@ -7422,7 +7655,7 @@ QCC_sref_t QCC_RefToDef(QCC_ref_t *ref, pbool freetemps)
}
else
idx = nullsref;
QCC_LoadFromPointer(tmp, ref->base, idx, ref->cast);
tmp = QCC_LoadFromPointer(ref->base, idx, ref->cast);
QCC_FreeTemp(idx);
if (freetemps)
QCC_PR_DiscardRef(ref);
@ -8359,6 +8592,28 @@ QCC_statement_t *QCC_Generate_OP_GOTO(void)
return st;
}
void PR_GenerateReturnOuts(void)
{
int i;
QCC_sref_t p;
QCC_def_t *local;
for (i = 0, local = pr.local_head.nextlocal; i < pr_scope->type->num_parms; i++, local = local->deftail->nextlocal)
{
if (!pr_scope->type->params[i].out)
continue;
if (i > MAX_PARMS)
p = extra_parms[i-MAX_PARMS];
else
{
p.sym = &def_parms[i];
p.ofs = 0;
p.cast = type_vector;
}
QCC_StoreToSRef(p, QCC_MakeSRefForce(local, 0, local->type), local->type, false, false);
}
}
/*
============
PR_ParseStatement
@ -8410,6 +8665,7 @@ void QCC_PR_ParseStatement (void)
if (QCC_PR_CheckToken (";"))
{
PR_GenerateReturnOuts();
if (pr_scope->type->aux_type->type != ev_void)
QCC_PR_ParseWarning(WARN_MISSINGRETURNVALUE, "\'%s\' returned nothing, expected %s", pr_scope->name, pr_scope->type->aux_type->name);
if (opt_return_only)
@ -8440,12 +8696,14 @@ void QCC_PR_ParseStatement (void)
e = QCC_SupplyConversion(e, pr_scope->type->aux_type->type, true);
// QCC_PR_ParseWarning(WARN_WRONGRETURNTYPE, "\'%s\' returned %s, expected %s", pr_scope->name, e->type->name, pr_scope->type->aux_type->name);
}
PR_GenerateReturnOuts();
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_RETURN], e, nullsref, NULL));
QCC_PR_Expect (";");
return;
}
if (QCC_PR_CheckKeyword(keyword_exit, "exit"))
{
PR_GenerateReturnOuts();
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_DONE], nullsref, nullsref, NULL));
QCC_PR_Expect (";");
return;
@ -8973,6 +9231,8 @@ void QCC_PR_ParseStatement (void)
else
patch1->a.ofs = &statements[numstatements] - patch1; //the goto start part
oldst = numstatements;
QCC_ForceUnFreeDef(e.sym); //in the following code, e should still be live
for (i = cases; i < num_cases; i++)
{
@ -9099,6 +9359,10 @@ void QCC_PR_ParseStatement (void)
}
num_breaks = breaks;
}
//update the jumptable statements to hide as part of the switch itself.
while (oldst < numstatements)
statements[oldst++].linenum = patch1->linenum;
return;
}
@ -10641,6 +10905,8 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *typ
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], e, QCC_PR_DummyDef(pr_classtype, "self", pr_scope, 0, e2->ofs, false), NULL));
}*/
if (needsdone)
PR_GenerateReturnOuts();
QCC_PR_Statement (&pr_opcodes[OP_DONE], nullsref, nullsref, NULL);
}
else
@ -12564,7 +12830,7 @@ void QCC_PR_ParseDefs (char *classname)
gd_flags = 0;
if (isstatic)
gd_flags |= GDF_STATIC;
if (isconstant || (type->type == ev_function && !isvar))
if (isconstant || (type->type == ev_function && !isvar && !pr_scope))
gd_flags |= GDF_CONST;
if (!nosave)
gd_flags |= GDF_SAVED;

View File

@ -1935,7 +1935,7 @@ void QCC_PR_LexVector (void)
if (*pr_file_p == '\'' && i == 1)
{
if (i < 2)
QCC_PR_ParseWarning (WARN_FTE_SPECIFIC, "Bad vector");
QCC_PR_ParseWarning (WARN_FTE_SPECIFIC, "2d vector");
for (i++ ; i<3 ; i++)
pr_immediate.vector[i] = 0;
@ -3369,10 +3369,14 @@ pbool VARGS QCC_PR_PrintWarning (int type, const char *file, int line, const cha
if (!wnam)
wnam = "";
QCC_PR_PrintScope();
if (string)
QCC_PR_PrintScope();
if (type >= ERR_PARSEERRORS)
{
if (!file || !*file)
if (!string)
;
else if (!file || !*file)
printf (":: error%s: %s\n", wnam, string);
else if (flag_msvcstyle)
printf ("%s(%i) : error%s: %s\n", file, line, wnam, string);
@ -3382,7 +3386,9 @@ pbool VARGS QCC_PR_PrintWarning (int type, const char *file, int line, const cha
}
else if (qccwarningaction[type] == 2)
{ //-werror
if (!file || !*file)
if (!string)
;
else if (!file || !*file)
printf (": werror%s: %s\n", wnam, string);
else if (flag_msvcstyle)
printf ("%s(%i) : werror%s: %s\n", file, line, wnam, string);
@ -3392,7 +3398,9 @@ pbool VARGS QCC_PR_PrintWarning (int type, const char *file, int line, const cha
}
else
{
if (!file || !*file)
if (!string)
;
else if (!file || !*file)
printf (": warning%s: %s\n", wnam, string);
else if (flag_msvcstyle)
printf ("%s(%i) : warning%s: %s\n", file, line, wnam, string);
@ -3410,6 +3418,9 @@ pbool VARGS QCC_PR_Warning (int type, const char *file, int line, const char *er
if (!qccwarningaction[type])
return false;
if (!error)
return QCC_PR_PrintWarning(type, file, line, NULL);
va_start (argptr,error);
QC_vsnprintf (string,sizeof(string)-1, error,argptr);
va_end (argptr);
@ -3643,17 +3654,28 @@ pbool QCC_PR_CheckName(const char *string)
pbool QCC_PR_CheckKeyword(int keywordenabled, const char *string)
{
if (!keywordenabled)
return false;
if (flag_caseinsensitive)
if (pr_token[0] == '_' && pr_token[1] == '_')
{
if (stricmp (string, pr_token))
//lets just always go insensitive with a leading underscore pair.
if (stricmp(string, pr_token+2))
return false;
QCC_PR_Lex ();
return true;
}
else
{
if (STRCMP(string, pr_token))
if (!keywordenabled)
return false;
if (flag_caseinsensitive)
{
if (stricmp (string, pr_token))
return false;
}
else
{
if (STRCMP(string, pr_token))
return false;
}
}
QCC_PR_Lex ();
return true;
@ -3833,6 +3855,8 @@ int typecmp_lax(QCC_type_t *a, QCC_type_t *b)
{
if (a->params[t].type->type != b->params[t].type->type)
return 1;
if (a->params[t].out != b->params[t].out)
return 1;
//classes/structs/unions are matched on class names rather than the contents of the class
//it gets too painful otherwise, with recursive definitions.
if (a->params[t].type->type == ev_entity || a->params[t].type->type == ev_struct || a->params[t].type->type == ev_union)
@ -3936,6 +3960,8 @@ char *TypeName(QCC_type_t *type, char *buffer, int buffersize)
Q_strlcat(buffer, "(", buffersize);
for (i = 0; i < type->num_parms; )
{
if (type->params[i].out)
Q_strlcat(buffer, "inout ", buffersize);
if (type->params[i].optional)
Q_strlcat(buffer, "optional ", buffersize);
args--;
@ -4111,6 +4137,11 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
break;
}
if (QCC_PR_CheckKeyword(keyword_inout, "inout"))
paramlist[numparms].out = true;
else
paramlist[numparms].out = false;
if (QCC_PR_CheckKeyword(keyword_optional, "optional"))
{
paramlist[numparms].optional = true;
@ -4232,7 +4263,7 @@ QCC_type_t *QCC_PR_ParseFunctionTypeReacc (int newtype, QCC_type_t *returntype)
break;
// type->name = "FUNC PARAMETER";
paramlist[numparms].out = false;
paramlist[numparms].optional = false;
paramlist[numparms].ofs = 0;
paramlist[numparms].arraysize = 0;
@ -4306,6 +4337,7 @@ QCC_type_t *QCC_PR_GenFunctionType (QCC_type_t *rettype, QCC_type_t **args, char
p->paramname = qccHunkAlloc(strlen(argnames[i])+1);
strcpy(p->paramname, argnames[i]);
p->type = args[i];
p->out = 0;
p->optional = false;
p->ofs = 0;
p->arraysize = 0;
@ -4356,8 +4388,6 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
}
if (QCC_PR_CheckToken ("."))
{
newt = QCC_PR_NewType("FIELD_TYPE", ev_field, false);
//.float *foo; is annoying.
//technically it is a pointer to a .float
//most people will want a .(float*) foo;
@ -4366,14 +4396,19 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
//this is pretty much an evil syntax hack.
if (QCC_PR_CheckToken ("*"))
{
newt->aux_type = QCC_PR_NewType("POINTER TYPE", ev_pointer, false);
newt->aux_type->aux_type = QCC_PR_ParseType (false, false);
newt->aux_type->size = newt->aux_type->aux_type->size;
type = QCC_PR_NewType("POINTER TYPE", ev_pointer, false);
type->aux_type = QCC_PR_ParseType (false, false);
type->size = type->aux_type->size;
}
else
newt->aux_type = QCC_PR_ParseType (false, false);
type = QCC_PR_ParseType (false, false);
name = qccHunkAlloc(strlen(type->name)+2);
*name = '.';
strcpy(name+1, type->name);
newt = QCC_PR_NewType(name, ev_field, false);
newt->aux_type = type;
newt->size = newt->aux_type->size;
if (newtype)
@ -4878,6 +4913,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
parms = realloc(parms, sizeof(*parms) * (numparms+1));
parms[numparms].ofs = 0;
parms[numparms].out = false;
parms[numparms].optional = false;
parms[numparms].paramname = parmname;
parms[numparms].arraysize = arraysize;
@ -4918,8 +4954,8 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
found = true;
break;
}
if ((unsigned int)basicindex < pp[i].ofs+1) //if we found one with the index
basicindex = pp[i].ofs+1; //make sure we don't union it.
if ((unsigned int)basicindex < pp[i].ofs+(pp[i].arraysize?pp[i].arraysize:1)) //if we found one with the index
basicindex = pp[i].ofs+(pp[i].arraysize?pp[i].arraysize:1); //make sure we don't union it.
}
}
}
@ -4940,13 +4976,15 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
if (!d)
{
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, 0, GDF_CONST);
for (i = 0; (unsigned int)i < newparm->size; i++)
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, arraysize, GDF_CONST);
for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
d->symboldata[i]._int = pr.size_fields+i;
pr.size_fields += i;
d->referenced = true; //always referenced, so you can inherit safely.
}
else if (d->arraysize != arraysize)
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
}
QCC_FreeDef(d);
@ -4954,7 +4992,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
//actually, that seems pointless.
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, classname, parmname);
// printf("define %s -> %s\n", membername, d->name);
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, 0, d, 0, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0));
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, arraysize, d, 0, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0));
d->referenced = true; //always referenced, so you can inherit safely.
}
@ -5050,6 +5088,9 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
arraysize = 0;
while (QCC_PR_CheckToken("*"))
newparm = QCC_PointerTypeTo(newparm);
if (!QCC_PR_CheckToken(";"))
{
parmname = qccHunkAlloc(strlen(pr_token)+1);
@ -5067,6 +5108,12 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
else
parmname = "";
if (newparm == newt || ((newparm->type == ev_struct || newparm->type == ev_union) && !newparm->size))
{
QCC_PR_ParseWarning(ERR_NOTANAME, "type %s not fully defined yet", newparm->name);
continue;
}
parms = realloc(parms, sizeof(*parms) * (numparms+1));
if (structtype == ev_union)
@ -5081,6 +5128,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
newt->size += newparm->size*(arraysize?arraysize:1);
}
parms[numparms].arraysize = arraysize;
parms[numparms].out = false;
parms[numparms].optional = false;
parms[numparms].paramname = parmname;
parms[numparms].type = newparm;

View File

@ -1378,6 +1378,7 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell)
QCC_def_t *def;
int fno;
int line;
int best, bestline;
char *macro = QCC_PR_CheckCompConstTooltip(defname, buffer, buffer + sizeof(buffer));
if (macro && *macro)
return macro;
@ -1393,6 +1394,81 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell)
line = SendMessage(editor->editpane, SCI_LINEFROMPOSITION, pos, 0);
for (best = 0,bestline=0, fno = 1; fno < numfunctions; fno++)
{
if (line > functions[fno].line && bestline < functions[fno].line)
{
if (!strcmp(editor->filename, functions[fno].file))
{
best = fno;
bestline = functions[fno].line;
}
}
}
if (best)
{
if (strstr(functions[best].name, "::"))
{
QCC_type_t *type;
char tmp[256];
char *c;
QC_strlcpy(tmp, functions[best].name, sizeof(tmp));
c = strstr(tmp, "::");
if (c)
*c = 0;
type = QCC_TypeForName(tmp);
if (type->type == ev_entity)
{
QCC_def_t *def;
QC_snprintfz(tmp, sizeof(tmp), "%s::__m%s", type->name, term);
for (fno = 0, def = NULL; fno < sourcefilesnumdefs && !def; fno++)
{
for (def = sourcefilesdefs[fno]; def; def = def->next)
{
if (def->scope && def->scope != &functions[best])
continue;
// OutputDebugString(def->name);
// OutputDebugString("\n");
if (!strcmp(def->name, tmp))
{
//FIXME: look at the scope's function to find the start+end of the function and filter based upon that, to show locals
break;
}
}
}
if (def && def->type->type == ev_field)
{
// QC_strlcpy(tmp, term, sizeof(tmp));
QC_snprintfz(term, sizeof(term), "self.%s", tmp);
}
else
{
for (fno = 0, def = NULL; fno < sourcefilesnumdefs && !def; fno++)
{
for (def = sourcefilesdefs[fno]; def; def = def->next)
{
if (def->scope && def->scope != &functions[best])
continue;
if (!strcmp(def->name, term))
{
//FIXME: look at the scope's function to find the start+end of the function and filter based upon that, to show locals
break;
}
}
}
if (def && def->type->type == ev_field)
{
QC_strlcpy(tmp, term, sizeof(tmp));
QC_snprintfz(term, sizeof(term), "self.%s", tmp);
}
}
}
}
}
//FIXME: we may need to display types too
for (fno = 0, def = NULL; fno < sourcefilesnumdefs && !def; fno++)
{
@ -4407,7 +4483,7 @@ int GrepSubFiles(HTREEITEM node, char *string)
{
HTREEITEM ch, p;
char fullname[1024];
char parentstring[256], *sl;
char parentstring[256];
int pl, nl;
TV_ITEM parent;
int found = 0;
@ -4430,14 +4506,17 @@ int GrepSubFiles(HTREEITEM node, char *string)
pl = strlen(parent.pszText);
if (nl + 1 + pl + 1 > sizeof(fullname))
return found;
p = TreeView_GetParent(projecttree, p);
if (!p && *fullname)
break;
//ignore the root node, unless we're actually querying that root node.
memmove(fullname+pl+1, fullname, nl+1);
memcpy(fullname, parent.pszText, pl);
fullname[pl] = nl?'/':'\0';
p = TreeView_GetParent(projecttree, p);
}
//skip the leading progs.src/ if its there, because that's an abstraction and does not match the filesystem.
sl = strchr(fullname, '/');
found += Grep(sl?sl+1:fullname, string);
found += Grep(fullname, string);
ch = TreeView_GetChild(projecttree, node);
found += GrepSubFiles(ch, string);

View File

@ -196,6 +196,11 @@ struct {
{" F308", WARN_TYPEMISMATCHREDECOPTIONAL},
{" F309", WARN_IGNORECOMMANDLINE},
{" F310", WARN_MISUSEDAUTOCVAR},
{" F311", WARN_FTE_SPECIFIC},
{" F208", WARN_NOTREFERENCEDCONST},
{" F209", WARN_EXTRAPRECACHE},
{" F210", WARN_NOTPRECACHED},
//frikqcc errors
//Q608: PrecacheSound: numsounds
@ -300,6 +305,7 @@ compiler_flag_t compiler_flag[] = {
{&keyword_shared, defaultkeyword, "shared", "Keyword: shared", "Disables the 'shared' keyword."}, //mark global to be copied over when progs changes (part of FTE_MULTIPROGS)
{&keyword_state, nondefaultkeyword,"state", "Keyword: state", "Disables the 'state' keyword."},
{&keyword_optional, defaultkeyword,"optional", "Keyword: optional", "Disables the 'optional' keyword."},
{&keyword_inout, nondefaultkeyword,"inout", "Keyword: inout", "Disables the 'inout' keyword."},
{&keyword_string, defaultkeyword, "string", "Keyword: string", "Disables the 'string' keyword."},
{&keyword_struct, defaultkeyword, "struct", "Keyword: struct", "Disables the 'struct' keyword."},
{&keyword_switch, defaultkeyword, "switch", "Keyword: switch", "Disables the 'switch' keyword."},
@ -749,7 +755,7 @@ int WriteBodylessFuncs (int handle)
{
if (d->type->type == ev_function && !d->scope)// function parms are ok
{
if (!(d->initialized & 1) && d->referenced)
if ((d->initialized == 2) && d->referenced)
{
SafeWrite(handle, d->name, strlen(d->name)+1);
ret++;
@ -817,13 +823,13 @@ void QCC_FinaliseDef(QCC_def_t *def)
for (prev = def, sub = prev->next; prev != def->deftail; sub = (prev=sub)->next)
{
if (sub->referenced)
def->referenced=true;
def->referenced=true; //if one child is referenced, the composite is referenced
else if (!sub->referenced && ignoreone)
ignoreone = false;
else
sub->referenced |= def->referenced;
}
if (!def->referenced)
if (!def->referenced) //okay, at least one child was refrenced, lets just flag all as referenced to silence warnings about vec_z being unused
for (prev = def, sub = prev->next; prev != def->deftail; sub = (prev=sub)->next)
sub->referenced = true;
}
@ -834,8 +840,8 @@ void QCC_FinaliseDef(QCC_def_t *def)
sub->referenced |= def->referenced;
}
}
else if (def->symbolheader) //if a child symbol is referenced, mark the entire parent as referenced too. this avoids vec_x+vec_y with no vec or vec_z from generating warnings about vec being unreferenced
def->symbolheader->referenced |= def->referenced;
// else if (def->symbolheader) //if a child symbol is referenced, mark the entire parent as referenced too. this avoids vec_x+vec_y with no vec or vec_z from generating warnings about vec being unreferenced
// def->symbolheader->referenced |= def->referenced;
if (!def->symbolheader->used)
{
@ -940,11 +946,12 @@ pbool QCC_WriteData (int crc)
pbool debugtarget = false;
pbool types = false;
int outputsttype = PST_DEFAULT;
int warnedunref = 0;
int dupewarncount = 0;
int *statement_linenums;
void *funcdata;
size_t funcdatasize;
extern char *basictypenames[];
if (numstatements==1 && numfunctions==1 && numglobaldefs==1 && numfielddefs==1)
@ -1136,14 +1143,27 @@ pbool QCC_WriteData (int crc)
}
else if (functions[i].firstlocal)
{
funcs[i].parm_start = functions[i].firstlocal->ofs;
for (local = functions[i].firstlocal, p = 0; local && p < MAX_PARMS && p < functions[i].type->num_parms; local = local->deftail->nextlocal, p++)
funcs[i].parm_start = 0;
for (local = functions[i].firstlocal, p = 0; local && p < MAX_PARMS && p < functions[i].type->num_parms; local = local->deftail->nextlocal)
{
if (!local->used)
{ //all params should have been assigned space. logically we could have safely omitted the last ones, but blurgh.
QCC_PR_Warning(ERR_INTERNAL, strings + local->s_file, local->s_line, "Argument %s was not marked used.\n", local->name);
continue;
}
if (!p)
funcs[i].parm_start = local->ofs;
funcs[i].locals += local->type->size;
funcs[i].parm_size[p] = local->type->size;
funcs[i].parm_size[p++] = local->type->size;
}
for (; local && !local->used; local = local->nextlocal)
;
if (!p && local)
funcs[i].parm_start = local->ofs;
for (; local; local = local->nextlocal)
funcs[i].locals += local->type->size;
if (local->used)
funcs[i].locals += local->type->size;
funcs[i].numparms = p;
}
else
@ -1160,6 +1180,9 @@ pbool QCC_WriteData (int crc)
funcs[i].locals = PRLittleLong(funcs[i].locals);
funcs[i].numparms = PRLittleLong(funcs[i].numparms);
if (funcs[i].locals && !funcs[i].parm_start)
QCC_PR_Warning(0, strings + funcs[i].s_file, functions[i].line, "%s:%i: func %s @%i locals@%i+%i, %i parms\n", strings+funcs[i].s_file, 0, strings+funcs[i].s_name, funcs[i].first_statement, funcs[i].parm_start, funcs[i].locals, funcs[i].numparms);
#ifdef DEBUG_DUMP
printf("code: %s:%i: func %s @%i locals@%i+%i, %i parms\n", strings+funcs[i].s_file, 0, strings+funcs[i].s_name, funcs[i].first_statement, funcs[i].parm_start, funcs[i].locals, funcs[i].numparms);
#endif
@ -1172,7 +1195,7 @@ pbool QCC_WriteData (int crc)
Sys_Error("structtype error");
}
for (warnedunref = 0, def = pr.def_head.next ; def ; def = def->next)
for (dupewarncount = 0, def = pr.def_head.next ; def ; def = def->next)
{
if ((def->type->type == ev_struct || def->type->type == ev_union || def->arraysize) && def->deftail)
{
@ -1221,13 +1244,12 @@ pbool QCC_WriteData (int crc)
{
int wt = def->constant?WARN_NOTREFERENCEDCONST:WARN_NOTREFERENCED;
pr_scope = def->scope;
if (strcmp(def->name, "IMMEDIATE") && qccwarningaction[wt])
if (!strncmp(def->name, "spawnfunc_", 10))
; //no warnings from unreferenced entry points.
else if (strcmp(def->name, "IMMEDIATE") && qccwarningaction[wt] && !(def->type->type == ev_function && def->symbolheader->timescalled) && !def->symbolheader->used)
{
char typestr[256];
if (warnedunref++ >= 10 && !verbose)
pr_warning_count++;
else
QCC_PR_Warning(wt, strings + def->s_file, def->s_line, "%s %s no references.", TypeName(def->type, typestr, sizeof(typestr)), def->name);
QCC_PR_Warning(wt, strings + def->s_file, def->s_line, (dupewarncount++ >= 10 && !verbose)?NULL:"%s %s no references.", TypeName(def->type, typestr, sizeof(typestr)), def->name);
}
pr_scope = NULL;
@ -1351,8 +1373,8 @@ pbool QCC_WriteData (int crc)
#endif
}
if (warnedunref > 10 && !verbose)
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "suppressed %i more warnings about unreferenced variables, as you clearly don't care about the first 10.", warnedunref-10);
if (dupewarncount > 10 && !verbose)
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "suppressed %i more warnings about unreferenced variables, as you clearly don't care about the first 10.", dupewarncount-10);
for (i = 0; i < numglobaldefs; i++)
{
@ -1405,13 +1427,26 @@ pbool QCC_WriteData (int crc)
QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals - %i\nAdd \"MAX_GLOBALS\" \"%i\" to qcc.cfg", numglobaldefs, (numglobaldefs+32768)&~32767);
dupewarncount = 0;
for (i = 0; i < nummodels; i++)
{
if (!precache_model[i].used)
QCC_PR_Warning(WARN_EXTRAPRECACHE, precache_model[i].filename, precache_model[i].fileline, "Model \"%s\" was precached but not directly used", precache_model[i].name);
dupewarncount+=QCC_PR_Warning(WARN_EXTRAPRECACHE, precache_model[i].filename, precache_model[i].fileline, (dupewarncount>10&&!verbose)?NULL:"Model \"%s\" was precached but not directly used%s", precache_model[i].name, dupewarncount?"":" (annotate the usage with the used_model intrinsic to silence this warning)");
else if (!precache_model[i].block)
QCC_PR_Warning(WARN_NOTPRECACHED, precache_model[i].filename, precache_model[i].fileline, "Model \"%s\" was used but not precached", precache_model[i].name);
dupewarncount+=QCC_PR_Warning(WARN_NOTPRECACHED, precache_model[i].filename, precache_model[i].fileline, (dupewarncount>10&&!verbose)?NULL:"Model \"%s\" was used but not precached", precache_model[i].name);
}
for (i = 0; i < numsounds; i++)
{
if (!precache_sound[i].used)
dupewarncount+=QCC_PR_Warning(WARN_EXTRAPRECACHE, precache_sound[i].filename, precache_sound[i].fileline, (dupewarncount>10&&!verbose)?NULL:"Sound \"%s\" was precached but not directly used", precache_sound[i].name, dupewarncount?"":" (annotate the usage with the used_sound intrinsic to silence this warning)");
else if (!precache_sound[i].block)
dupewarncount+=QCC_PR_Warning(WARN_NOTPRECACHED, precache_sound[i].filename, precache_sound[i].fileline, (dupewarncount>10&&!verbose)?NULL:"Sound \"%s\" was used but not precached", precache_sound[i].name);
}
if (dupewarncount > 10 && !verbose)
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "suppressed %i more warnings about precaches.", dupewarncount-10);
//PrintStrings ();
//PrintFunctions ();
//PrintFields ();
@ -1801,6 +1836,10 @@ strofs = (strofs+3)&~3;
progs.ofs_types = 0;
progs.numtypes = 0;
progs.ofsbodylessfuncs = SafeSeek (h, 0, SEEK_CUR);
progs.numbodylessfuncs = WriteBodylessFuncs(h);
switch(qcc_targetformat)
{
case QCF_QTEST:
@ -1824,9 +1863,6 @@ strofs = (strofs+3)&~3;
else
progs.secondaryversion = PROG_SECONDARYVERSION16;
progs.ofsbodylessfuncs = SafeSeek (h, 0, SEEK_CUR);
progs.numbodylessfuncs = WriteBodylessFuncs(h);
if (debugtarget && statement_linenums)
{
progs.ofslinenums = SafeSeek (h, 0, SEEK_CUR);
@ -1874,6 +1910,10 @@ strofs = (strofs+3)&~3;
break;
}
if (progs.version != PROG_EXTENDEDVERSION && progs.numbodylessfuncs)
printf ("WARNING: progs format cannot handle extern functions\n");
if (verbose)
printf ("%6i TOTAL SIZE\n", (int)SafeSeek (h, 0, SEEK_CUR));
@ -3253,7 +3293,10 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
for (j = 0; j < ERR_PARSEERRORS; j++)
if (qccwarningaction[j] == WA_IGNORE)
{
qccwarningaction[j] = WA_WARN;
if (j != WARN_FTE_SPECIFIC && //kinda annoying when its actually valid code.
j != WARN_NOTREFERENCEDCONST && //warning about every single constant is annoying as heck. note that this includes both stuff like MOVETYPE_ and builtins.
j != WARN_EXTRAPRECACHE) //we can't guarentee that we can parse this correctly. this warning is thus a common false positive. its available with -Wextra, and there's intrinsics to reduce false positives.
qccwarningaction[j] = WA_WARN;
}
}
else if (!stricmp(myargv[i]+2, "extra"))
@ -3427,7 +3470,7 @@ void QCC_SetDefaultProperties (void)
qccwarningaction[WARN_EVILPREPROCESSOR] = WA_WARN;//FIXME: make into WA_ERROR;
if (qcc_targetformat == QCF_HEXEN2 || qcc_targetformat == QCF_FTEH2)
qccwarningaction[WARN_CASEINSENSITIVEFRAMEMACRO] = WA_IGNORE;
qccwarningaction[WARN_CASEINSENSITIVEFRAMEMACRO] = WA_IGNORE; //hexenc consides these fair game.
//Check the command line
QCC_PR_CommandLinePrecompilerOptions();
@ -4187,7 +4230,7 @@ void QCC_FinishCompile(void)
if (optres_test2)
printf("optres_test2 %i\n", optres_test2);
printf("numtemps %i\n", tempsused);
printf("numtemps %u\n", (unsigned)tempsused);
}
if (!flag_msvcstyle)
printf("Done. %i warnings\n", pr_warning_count);

View File

@ -629,7 +629,6 @@ void NPP_NQFlush(void)
if (!bufferlen)
return;
switch(majortype)
{
case svc_cdtrack:
@ -1543,6 +1542,36 @@ void NPP_NQWriteEntity(int dest, int data) //replacement write func (nq to qw)
#ifdef NQPROT
float NPP_ReadFloat(qbyte *buf)
{
union
{
float f;
qbyte b[4];
} u;
memcpy(u.b, buf, sizeof(u.f));
return LittleFloat(u.f);
}
short NPP_ReadShort(qbyte *buf)
{
union
{
short s;
qbyte b[2];
} u;
memcpy(u.b, buf, sizeof(u.s));
return LittleShort(u.s);
}
unsigned short NPP_ReadUShort(qbyte *buf)
{
union
{
unsigned short s;
qbyte b[2];
} u;
memcpy(u.b, buf, sizeof(u.s));
return LittleShort(u.s);
}
//qw to nq translation is only useful if we allow nq clients to connect.
@ -1568,7 +1597,9 @@ void NPP_QWFlush(void)
Con_Printf("QWFlush: svc_cdtrack wasn't the right length\n");
else
{
b = 0;
//qw cdtracks have only a loop byte.
//nq has initial+loop values.
b = (bufferlen==2)?buffer[1]:0;
NPP_AddData(&b, sizeof(qbyte));
}
break;
@ -1596,13 +1627,36 @@ void NPP_QWFlush(void)
ClientReliableCheckBlock(cl, 1);
ClientReliableWrite_Byte(cl, svc_intermission);
org[0] = (*(short*)&buffer[1])/8.0f;
org[1] = (*(short*)&buffer[1+2])/8.0f;
org[2] = (*(short*)&buffer[1+4])/8.0f;
i = 1;
if (destprim->coordsize == 4)
{
org[0] = NPP_ReadFloat(buffer+i+0);
org[1] = NPP_ReadFloat(buffer+i+4);
org[2] = NPP_ReadFloat(buffer+i+8);
i += 12;
}
else
{
org[0] = NPP_ReadShort(buffer+i+0) / 8.0;
org[1] = NPP_ReadShort(buffer+i+2) / 8.0;
org[2] = NPP_ReadShort(buffer+i+4) / 8.0;
i += 6;
}
ang[0] = (*(qbyte*)&buffer[7])*360.0/255;
ang[1] = (*(qbyte*)&buffer[7+1])*360.0/255;
ang[2] = (*(qbyte*)&buffer[7+2])*360.0/255;
if (destprim->anglesize == 2)
{
ang[0] = NPP_ReadUShort(buffer+i+0)*360.0/0xffff;
ang[1] = NPP_ReadUShort(buffer+i+2)*360.0/0xffff;
ang[2] = NPP_ReadUShort(buffer+i+4)*360.0/0xffff;
i += 6;
}
else
{
ang[0] = (*(qbyte*)&buffer[i+0])*360.0/0xff;
ang[1] = (*(qbyte*)&buffer[i+1])*360.0/0xff;
ang[2] = (*(qbyte*)&buffer[i+2])*360.0/0xff;
i += 3;
}
//move nq players to origin + angle
VectorCopy(org, cl->edict->v->origin);
@ -1913,7 +1967,7 @@ void NPP_QWWriteByte(int dest, qbyte data) //replacement write func (nq to qw)
protocollen = 1;
break;
case svc_intermission:
protocollen = 10;
protocollen = 1 + destprim->coordsize*3 + destprim->anglesize*3;
break;
case svc_finale:
protocollen = 2;

View File

@ -1392,7 +1392,7 @@ void Q_InitProgs(void)
for (j = 0; j < maps; j++)
{
f = COM_Parse(f);
if (!Q_strcasecmp(sv.name, com_token))
if (!Q_strcasecmp(svs.name, com_token))
{
f = COM_Parse(f);
strcpy(addons, com_token);
@ -1592,7 +1592,7 @@ void Q_InitProgs(void)
}
//progs depended on by maps.
a = as = COM_LoadStackFile(va("maps/%s.inf", sv.name), addons, sizeof(addons), NULL);
a = as = COM_LoadStackFile(va("maps/%s.inf", svs.name), addons, sizeof(addons), NULL);
if (a)
{
as = strstr(a, "qwprogs=");
@ -3033,6 +3033,7 @@ static void QCBUILTIN PF_sound (pubprogfuncs_t *prinst, struct globalvars_s *pr_
float attenuation;
int pitchadj;
int flags;
float timeofs;
entity = G_EDICT(prinst, OFS_PARM0);
channel = G_FLOAT(OFS_PARM1);
@ -3045,7 +3046,7 @@ static void QCBUILTIN PF_sound (pubprogfuncs_t *prinst, struct globalvars_s *pr_
pitchadj = 0;
if (svprogfuncs->callargc > 6)
{
flags = G_FLOAT(OFS_PARM5);
flags = G_FLOAT(OFS_PARM6);
if (channel < 0)
channel = 0;
}
@ -3056,6 +3057,7 @@ static void QCBUILTIN PF_sound (pubprogfuncs_t *prinst, struct globalvars_s *pr_
//demangle it so the upper bits are still useful.
channel = (channel & 7) | ((channel & 0x1f0) >> 1);
}
timeofs = (svprogfuncs->callargc>7)?G_FLOAT(OFS_PARM7):0;
if (volume < 0) //erm...
return;
@ -3063,11 +3065,11 @@ static void QCBUILTIN PF_sound (pubprogfuncs_t *prinst, struct globalvars_s *pr_
if (volume > 255)
volume = 255;
//should probably be an argument instead, but whatever.
if (flags & 1)
channel |= 256;
//shift the reliable flag to 256 instead.
SVQ1_StartSound (NULL, (wedict_t*)entity, channel, sample, volume, attenuation, pitchadj);
SVQ1_StartSound (NULL, (wedict_t*)entity, channel, sample, volume, attenuation, pitchadj, timeofs);
}
static void QCBUILTIN PF_pointsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -3087,7 +3089,7 @@ static void QCBUILTIN PF_pointsound(pubprogfuncs_t *prinst, struct globalvars_s
else
pitchpct = 0;
SVQ1_StartSound (origin, sv.world.edicts, 0, sample, volume, attenuation, pitchpct);
SVQ1_StartSound (origin, sv.world.edicts, 0, sample, volume, attenuation, pitchpct, 0);
}
//an evil one from telejano.
@ -6087,7 +6089,6 @@ string readmcmd (string str)
static void QCBUILTIN PF_readcmd (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *s;
static char output[8000];
extern char outputbuf[];
extern redirect_t sv_redirected;
extern int sv_redirectedlang;
@ -6106,14 +6107,12 @@ static void QCBUILTIN PF_readcmd (pubprogfuncs_t *prinst, struct globalvars_s *p
SV_BeginRedirect(RD_OBLIVION, TL_FindLanguage(""));
Cbuf_Execute();
Q_strncpyz(output, outputbuf, sizeof(output));
Con_Printf("PF_readcmd: %s\n%s", s, outputbuf);
G_INT(OFS_RETURN) = (int)PR_TempString(prinst, outputbuf);
SV_EndRedirect();
if (old != RD_NONE)
SV_BeginRedirect(old, oldl);
Con_Printf("PF_readcmd: %s\n%s", s, output);
G_INT(OFS_RETURN) = (int)PR_SetString(prinst, output);
}
/*
@ -6647,11 +6646,18 @@ void SV_AddDebugPolygons(void)
int i;
if (gfuncs.AddDebugPolygons)
{
#ifdef PROGS_DAT
extern qboolean csqc_dp_lastwas3d;
csqc_dp_lastwas3d = true;
#endif
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv.world.edicts);
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);
#ifdef PROGS_DAT
csqc_dp_lastwas3d = false;
#endif
}
}
@ -7564,7 +7570,7 @@ static void QCBUILTIN PF_h2StopSound(pubprogfuncs_t *prinst, struct globalvars_s
entity = G_EDICT(prinst, OFS_PARM0);
channel = G_FLOAT(OFS_PARM1);
SVQ1_StartSound (NULL, (wedict_t*)entity, channel, "", 1, 0, 0);
SVQ1_StartSound (NULL, (wedict_t*)entity, channel, "", 1, 0, 0, 0);
}
static void QCBUILTIN PF_h2updatesoundpos(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -9227,7 +9233,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"qtest_setabssize",PF_setsize, 5, 0, 0, 0, D("void(entity e, vector min, vector max)", "qtest"), true},
{"breakpoint", PF_break, 6, 6, 6, 0, D("void()", "Trigger a debugging event. FTE will break into the qc debugger. Other engines may crash with a debug execption.")},
{"random", PF_random, 7, 7, 7, 0, D("float()", "Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays.")},
{"sound", PF_sound, 8, 8, 8, 0, D("void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags)", "Starts a sound centered upon the given entity.\nchan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample\n'samp' must have been precached first\nif specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed.\nflags&1 means the sound should be sent reliably.")},
{"sound", PF_sound, 8, 8, 8, 0, D("void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags, optional float timeofs)", "Starts a sound centered upon the given entity.\nchan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample\n'samp' must have been precached first\nif specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed.\nIf flags is specified, the reliable flag in the channels argument is used for additional channels. Flags should be made from SOUNDFLAG_* constants\ntimeofs should be negative in order to provide a delay before the sound actually starts.")},
{"normalize", PF_normalize, 9, 9, 9, 0, D("vector(vector v)", "Shorten or lengthen a direction vector such that it is only one quake unit long.")},
{"error", PF_error, 10, 10, 10, 0, D("void(string e)", "Ends the game with an easily readable error message.")},
{"objerror", PF_objerror, 11, 11, 11, 0, D("void(string e)", "Displays a non-fatal easily readable error message concerning the self entity, including a field dump. self will be removed!")},
@ -9537,6 +9543,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"strcasecmp", PF_strncasecmp, 0, 0, 0, 229, D("float(string s1, string s2)", "Compares the two strings without case sensitivity.\nReturns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon.")},
{"strncasecmp", PF_strncasecmp, 0, 0, 0, 230, D("float(string s1, string s2, float len, optional float s1ofs, optional float s2ofs)", "Compares up to 'len' chars in the two strings without case sensitivity. s1ofs allows you to treat s2 as a substring to compare against, or should be 0.\nReturns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon.")},
//END FTE_STRINGS
{"strtrim", PF_strtrim, 0, 0, 0, 0, D("string(string s)", "Trims the whitespace from the start+end of the string.")},
//FTE_CALLTIMEOFDAY
{"calltimeofday", PF_calltimeofday, 0, 0, 0, 231, D("void()", "Asks the engine to instantly call the qc's 'timeofday' function, before returning. For compatibility with mvdsv.\ntimeofday should have the prototype: void(float secs, float mins, float hour, float day, float mon, float year, string strvalue)\nThe strftime builtin is more versatile and less weird.")},
@ -9579,10 +9586,12 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"sqlversion", PF_sqlversion, 0, 0, 0, 257, "string(float serveridx)"}, // sqlversion (FTE_SQL)
{"sqlreadfloat", PF_sqlreadfloat, 0, 0, 0, 258, "float(float serveridx, float queryidx, float row, float column)"}, // sqlreadfloat (FTE_SQL)
{"stoi", PF_stoi, 0, 0, 0, 259, D("int(string)", "Converts the given string into an integer. Base 8, 10, or 16 is determined based upon the format of the string.")},
{"itos", PF_itos, 0, 0, 0, 260, D("string(int)", "Converts the passed integer into a base10 string.")},
{"stoi", PF_stoi, 0, 0, 0, 259, D("int(string)", "Converts the given string into a true integer. Base 8, 10, or 16 is determined based upon the format of the string.")},
{"itos", PF_itos, 0, 0, 0, 260, D("string(int)", "Converts the passed true integer into a base10 string.")},
{"stoh", PF_stoh, 0, 0, 0, 261, D("int(string)", "Reads a base-16 string (with or without 0x prefix) as an integer. Bugs out if given a base 8 or base 10 string. :P")},
{"htos", PF_htos, 0, 0, 0, 262, D("string(int)", "Formats an integer as a base16 string, with leading 0s and no prefix. Always returns 8 characters.")},
{"ftoi", PF_ftoi, 0, 0, 0, 0, D("int(float)", "Converts the given float into a true integer without depending on extended qcvm instructions.")},
{"itof", PF_itof, 0, 0, 0, 0, D("float(int)", "Converts the given true integer into a float without depending on extended qcvm instructions.")},
{"skel_create", PF_skel_create, 0, 0, 0, 263, D("float(float modlindex, optional float useabstransforms)", "Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model.\neg: self.skeletonobject = skel_create(self.modelindex);")}, // (FTE_CSQC_SKELETONOBJECTS)
{"skel_build", PF_skel_build, 0, 0, 0, 264, D("float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac)", "Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object.\nIf retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based.")}, // (FTE_CSQC_SKELETONOBJECTS)
@ -9654,7 +9663,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"dynamiclight_add",PF_Fixme, 0, 0, 0, 305, D("float(vector org, float radius, vector lightcolours, optional float style, optional string cubemapname, optional float pflags)", "Adds a temporary dlight, ready to be drawn via addscene. Cubemap orientation will be read from v_forward/v_right/v_up.")},// (EXT_CSQC)
//gonna expose these to ssqc as a debugging extension
{"R_BeginPolygon", PF_R_PolygonBegin,0,0, 0, 306, D("void(string texturename, optional float flags)", "Specifies the shader to use for the following polygons, along with optional flags.\nIf flags&4, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects.")},// (EXT_CSQC_???)
{"R_BeginPolygon", PF_R_PolygonBegin,0,0, 0, 306, D("void(string texturename, optional float flags, optional float is2d)", "Specifies the shader to use for the following polygons, along with optional flags.\nIf is2d, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects.")},// (EXT_CSQC_???)
{"R_PolygonVertex", PF_R_PolygonVertex,0,0, 0, 307, D("void(vector org, vector texcoords, vector rgb, float alpha)", "Specifies a polygon vertex with its various properties.")},// (EXT_CSQC_???)
{"R_EndPolygon", PF_R_PolygonEnd,0, 0, 0, 308, D("void()", "Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader.")},
@ -9763,6 +9772,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"memgetval", PF_memgetval, 0, 0, 0, 388, D("__variant(__variant *dst, float ofs)", "Looks up the 32bit value stored at a pointer-with-offset.")},
{"memsetval", PF_memsetval, 0, 0, 0, 389, D("void(__variant *dst, float ofs, __variant val)", "Changes the 32bit value stored at the specified pointer-with-offset.")},
{"memptradd", PF_memptradd, 0, 0, 0, 390, D("__variant*(__variant *base, float ofs)", "Perform some pointer maths. Woo.")},
{"memstrsize", PF_memstrsize, 0, 0, 0, 0, D("float(string s)", "strlen, except ignores utf-8")},
{"con_getset", PF_Fixme, 0, 0, 0, 391, D("string(string conname, string field, optional string newvalue)", "Reads or sets a property from a console object. The old value is returned. Iterrate through consoles with the 'next' field. Valid properties: title, name, next, unseen, markup, forceutf8, close, clear, hidden, linecount")},
{"con_printf", PF_Fixme, 0, 0, 0, 392, D("void(string conname, string messagefmt, ...)", "Prints onto a named console.")},
@ -9957,7 +9967,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"gettime", PF_gettime, 0, 0, 0, 519, "float(optional float timetype)"},
{"keynumtostring_omgwtf",PF_Fixme, 0, 0, 0, 520, "string(float keynum)"}, //excessive third version in dp's csqc.
{"findkeysforcommand",PF_Fixme, 0, 0, 0, 521, D("string(string command, optional float bindmap)", "Returns a list of keycodes that perform the given console command in a format that can only be parsed via tokenize (NOT tokenize_console). This only and always returns two values - if only one key is actually bound, -1 will be returned. The bindmap argument is listed for compatibility with dp-specific defs, but is ignored in FTE.")},
{"findkeysforcommandex",PF_Fixme, 0, 0, 0, 0, D("string(string command)", "Returns a list of key bindings in keyname format instead of keynums. Use tokenize to parse. This list may contain modifiers. May return large numbers of keys.")},
{"findkeysforcommandex",PF_Fixme, 0, 0, 0, 0, D("string(string command, optional float bindmap)", "Returns a list of key bindings in keyname format instead of keynums. Use tokenize to parse. This list may contain modifiers. May return large numbers of keys.")},
// {"initparticlespawner",PF_Fixme, 0, 0, 0, 522, "void(float max_themes)"},
// {"resetparticle", PF_Fixme, 0, 0, 0, 523, "void()"},
// {"particletheme", PF_Fixme, 0, 0, 0, 524, "void(float theme)"},
@ -9974,8 +9984,9 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//end mvdsv extras
//restart dp extras
// {"log", PF_Fixme, 0, 0, 0, 532, "float(string mname)", true},
{"getsoundtime", PF_Ignore, 0, 0, 0, 533, "float(entity e, float channel)"},
{"soundlength", PF_Ignore, 0, 0, 0, 534, "float(string sample)"},
{"soundupdate", PF_Fixme, 0, 0, 0, 0, D("float(entity e, float channel, string newsample, float volume, float attenuation, float pitchpct, float flags, float timeoffset)", "Changes the properties of the current sound being played on the given entity channel. newsample may be empty, and will be ignored in this case. timeoffset is relative to the current position (subtract the result of getsoundtime for absolute positions). Negative volume can be used to stop the sound. Return value is a fractional value based upon the number of audio devices that could be updated - test against TRUE rather than non-zero.")},
{"getsoundtime", PF_Ignore, 0, 0, 0, 533, D("float(entity e, float channel)", "Returns the current playback time of the sample on the given entity's channel. Beware CHAN_AUTO (in csqc, channels are not limited by network protocol).")},
{"soundlength", PF_Ignore, 0, 0, 0, 534, D("float(string sample)", "Provides a way to query the duration of a sound sample, allowing you to set up a timer to chain samples.")},
{"buf_loadfile", PF_buf_loadfile, 0, 0, 0, 535, D("float(string filename, strbuf bufhandle)", "Appends the named file into a string buffer (which must have been created in advance). The return value merely says whether the file was readable.")},
{"buf_writefile", PF_buf_writefile, 0, 0, 0, 536, D("float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings)", "Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer.")},
// {"bufstr_find", PF_Fixme, 0, 0, 0, 537, "float(float bufhandle, string match, float matchrule, float startpos)"},
@ -10021,8 +10032,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"getsurfacenumtriangles",PF_getsurfacenumtriangles,0,0,0, 628, "float(entity e, float s)"},
{"getsurfacetriangle",PF_getsurfacetriangle,0, 0, 0, 629, "vector(entity e, float s, float n)"},
// {"setkeybind", PF_Fixme, 0, 0, 0, 630, "float(float key, string bind, optional float bindmap)"},
{"getbindmaps", PF_Fixme, 0, 0, 0, 631, "vector()" STUB},
{"setbindmaps", PF_Fixme, 0, 0, 0, 632, "float(vector bm)" STUB},
{"getbindmaps", PF_Fixme, 0, 0, 0, 631, "vector()"},
{"setbindmaps", PF_Fixme, 0, 0, 0, 632, "float(vector bm)"},
{"crypto_getkeyfp", PF_Fixme, 0, 0, 0, 633, "string(string addr)" STUB},
{"crypto_getidfp", PF_Fixme, 0, 0, 0, 634, "string(string addr)" STUB},
{"crypto_getencryptlevel",PF_Fixme, 0, 0, 0, 635, "string(string addr)" STUB},
@ -10703,12 +10714,12 @@ void PR_DumpPlatform_f(void)
{"CSQC_Parse_Print", "void(string printmsg, float printlvl)", CS, "Gives the CSQC a chance to intercept sprint/bprint builtin calls. CSQC should filter by the client's current msg setting and then pass the message on to the print command, or handle them itself."},
{"CSQC_Parse_Event", "void()", CS, "Called when the client receives an SVC_CGAMEPACKET. The csqc should read the data or call the error builtin if it does not recognise the message."},
{"CSQC_InputEvent", "float(float evtype, float scanx, float chary, float devid)", CS, "Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time."},
{"CSQC_Input_Frame", "void()", CS, "Called just before each time clientcommandframe is updated. You can edit the input_* globals in order to apply your own player inputs within csqc, which may allow you a convienient way to pass certain info to ssqc."},
{"CSQC_Input_Frame", "__used void()", CS, "Called just before each time clientcommandframe is updated. You can edit the input_* globals in order to apply your own player inputs within csqc, which may allow you a convienient way to pass certain info to ssqc."},
{"CSQC_ConsoleCommand", "float(string cmd)", CS, "Called if the user uses any console command registed via registercommand."},
{"CSQC_ConsoleLink", "float(string text, string info)", CS, "Called if the user clicks a ^[text\\infokey\\infovalue^] link. Use infoget to read/check each supported key. Return true if you wish the engine to not attempt to handle the link itself."},
{"CSQC_Ent_Update", "void(float isnew)", CS},
{"CSQC_Ent_Remove", "void()", CS},
{"CSQC_Event_Sound", "float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod)", CS},
{"CSQC_Event_Sound", "float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod, float flags"/*", float timeofs*/")", CS},
// {"CSQC_ServerSound", "//void()", CS},
{"CSQC_LoadResource", "float(string resname, string restype)", CS, "Called each time some resource is being loaded. CSQC can invoke various draw calls to provide a loading screen, until WorldLoaded is called."},
{"CSQC_Parse_TempEntity", "float()", CS, "Please don't use this. Use CSQC_Parse_Event and multicasts instead."},
@ -10730,7 +10741,7 @@ void PR_DumpPlatform_f(void)
{"parm49, parm50, parm51, parm52, parm53, parm54, parm55, parm56, parm57, parm58, parm59, parm60, parm61, parm62, parm63, parm64", "float", QW|NQ},
{"dimension_send", "var float", QW|NQ, "Used by multicast functionality. Multicasts (and related builtins that multicast internally) will only be sent to players where (player.dimension_see & dimension_send) is non-zero."},
{"dimension_default", "//var float", QW|NQ, "Default dimension bitmask", 255},
{"physics_mode", "var float", QW|NQ|CS, "0: original csqc - physics are not run\n1: DP-compat. Thinks occur, but not true movetypes.\n2: movetypes occur just as they do in ssqc.", 2},
{"physics_mode", "__used var float", QW|NQ|CS, "0: original csqc - physics are not run\n1: DP-compat. Thinks occur, but not true movetypes.\n2: movetypes occur just as they do in ssqc.", 2},
{"gamespeed", "float", CS, "Set by the engine, this is the value of the sv_gamespeed cvar"},
{"numclientseats", "float", CS, "This is the number of splitscreen clients currently running on this client."},
{"drawfontscale", "var vector", CS|MENU, "Specifies a scaler for all text rendering. There are other ways to implement this.", 0, "'1 1 0'"},
@ -10826,6 +10837,10 @@ void PR_DumpPlatform_f(void)
{"CHAN_VOICE", "const float", QW|NQ|CS, NULL, CHAN_VOICE},
{"CHAN_ITEM", "const float", QW|NQ|CS, NULL, CHAN_ITEM},
{"CHAN_BODY", "const float", QW|NQ|CS, NULL, CHAN_BODY},
{"CHANF_RELIABLE", "const float", QW, NULL, 8},
{"SOUNDFLAG_RELIABLE", "const float", QW|NQ, NULL, 1},
// {"SOUNDFLAG_ABSOLUTEVOL", "const float", CS, NULL, 256},
{"ATTN_NONE", "const float", QW|NQ|CS, "Sounds with this attenuation can be heard throughout the map", ATTN_NONE},
{"ATTN_NORM", "const float", QW|NQ|CS, "Standard attenuation", ATTN_NORM},
@ -10901,6 +10916,7 @@ void PR_DumpPlatform_f(void)
{"SERVERKEY_PAUSESTATE","const string", CS, "1 if the server claimed to be paused. 0 otherwise", 0, "\"pausestate\""},
{"SERVERKEY_DLSTATE", "const string", CS, "The progress of any current downloads. Empty string if no download is active, otherwise a tokenizable string containing this info:\nfiles-remaining, total-size, unknown-sizes-flag, file-localname, file-remotename, file-percent, file-rate, file-received-bytes, file-total-bytes\nIf the current file info is omitted, then we are waiting for a download to start.", 0, "\"dlstate\""},
{"SERVERKEY_PROTOCOL", "const string", CS, "The protocol we are connected to the server with.", 0, "\"protocol\""},
{"SERVERKEY_MAXPLAYERS","const string", CS, "The protocol we are connected to the server with.", 0, "\"maxplayers\""},
// edict.flags
{"FL_FLY", "const float", QW|NQ|CS, NULL, FL_FLY},
@ -10950,6 +10966,7 @@ void PR_DumpPlatform_f(void)
{"EF_ADDITIVE", "const float", NQ|CS, NULL, NQEF_ADDITIVE},
{"EF_BLUE", "const float", QW|NQ|CS, NULL, EF_BLUE},
{"EF_RED", "const float", QW|NQ|CS, NULL, EF_RED},
{"EF_GREEN", "const float", QW|NQ|CS, NULL, EF_GREEN},
{"EF_FULLBRIGHT", "const float", QW|NQ|CS, NULL, EF_FULLBRIGHT},
{"EF_NODEPTHTEST", "const float", QW|NQ|CS, NULL, EF_NODEPTHTEST},

Some files were not shown because too many files have changed in this diff Show More