more cleanups: csqc now shares collision code with ssqc. Still lacks physics.

gl_rsurf.c has been split into gl specific and generic code - the d3d renderer can now draw the world.
ifdef removed the old server-side mvd playback which had been disabled all this time anyway.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3426 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2009-11-07 13:29:15 +00:00
parent 79a45e1a19
commit e6d1ae1a8f
47 changed files with 3872 additions and 6094 deletions

View File

@ -351,6 +351,7 @@ GLQUAKE_OBJS = \
gl_font.o \
gl_heightmap.o \
gl_rsurf.o \
r_surf.o \
ltface.o \
r_2d.o \
gl_screen.o \

View File

@ -49,7 +49,6 @@ static csqctreadstate_t *csqcthreads;
qboolean csqc_resortfrags;
qboolean csqc_drawsbar;
qboolean csqc_addcrosshair;
static int num_csqc_edicts;
static int csqc_fakereadbyte;
world_t csqc_world;
@ -128,6 +127,7 @@ typedef enum
#define CSQCRF_USEAXIS 16 //use v_forward/v_right/v_up as an axis/matrix - predraw is needed to use this properly
#define CSQCRF_NOSHADOW 32 //don't cast shadows upon other entities (can still be self shadowing, if the engine wishes, and not additive)
#define CSQCRF_FRAMETIMESARESTARTTIMES 64 //EXT_CSQC_1: frame times should be read as (time-frametime).
#define CSQCRF_NOAUTOADD 128 //EXT_CSQC_1: don't automatically add after predraw was called
//If I do it like this, I'll never forget to register something...
@ -182,7 +182,6 @@ typedef enum
globalfloat(player_localnum, "player_localnum"); /*float the entity number of the local player*/ \
globalfloat(intermission, "intermission"); /*float set when the client receives svc_intermission*/ \
globalvector(view_angles, "view_angles"); /*float set to the view angles at the start of each new frame (EXT_CSQC_1)*/ \
globalfloat(dpcompat_sbshowscores, "sb_showscores"); /*deprecated ask darkplaces people, its not part of the csqc standard */ \
\
globalvector(pmove_org, "pmove_org"); /*deprecated. read/written by runplayerphysics*/ \
globalvector(pmove_vel, "pmove_vel"); /*deprecated. read/written by runplayerphysics*/ \
@ -364,6 +363,9 @@ typedef struct csqcedict_s
int areanum; //q2bsp
int areanum2; //q2bsp
int headnode; //q2bsp
#endif
#ifdef USEODE
entityode_t ode;
#endif
qbyte solidtype;
/*the above is shared with ssqc*/
@ -372,8 +374,6 @@ typedef struct csqcedict_s
trailstate_t *trailstate;
} csqcedict_t;
static csqcedict_t *csqc_edicts; //consider this 'world'
static void CSQC_InitFields(void)
{ //CHANGING THIS FUNCTION REQUIRES CHANGES TO csqcentvars_t
@ -443,345 +443,6 @@ void skel_dodelete(void);
static model_t *CSQC_GetModelForIndex(int index);
static void CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers);
areanode_t cs_areanodes[AREA_NODES];
int cs_numareanodes;
#define CSEDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,csqcedict_t,area)
areanode_t *CS_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
{
areanode_t *anode;
vec3_t size;
vec3_t mins1, maxs1, mins2, maxs2;
anode = &cs_areanodes[cs_numareanodes];
cs_numareanodes++;
ClearLink (&anode->trigger_edicts);
ClearLink (&anode->solid_edicts);
if (depth == AREA_DEPTH)
{
anode->axis = -1;
anode->children[0] = anode->children[1] = NULL;
return anode;
}
VectorSubtract (maxs, mins, size);
if (size[0] > size[1])
anode->axis = 0;
else
anode->axis = 1;
anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
VectorCopy (mins, mins1);
VectorCopy (mins, mins2);
VectorCopy (maxs, maxs1);
VectorCopy (maxs, maxs2);
maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
anode->children[0] = CS_CreateAreaNode (depth+1, mins2, maxs2);
anode->children[1] = CS_CreateAreaNode (depth+1, mins1, maxs1);
return anode;
}
void CS_ClearWorld (void)
{
int i;
memset (cs_areanodes, 0, sizeof(cs_areanodes));
cs_numareanodes = 0;
if (cl.worldmodel)
CS_CreateAreaNode (0, cl.worldmodel->mins, cl.worldmodel->maxs);
else
{
vec3_t mins, maxs;
int i;
for (i = 0; i < 3; i++)
{
mins[i] = -4096;
maxs[i] = 4096;
}
CS_CreateAreaNode (0, mins, maxs);
}
for (i = 1; i < num_csqc_edicts; i++)
CS_LinkEdict((csqcedict_t*)EDICT_NUM(csqcprogs, i), false);
}
#define MAX_NODELINKS 256 //all this means is that any more than this will not touch.
static csqcedict_t *csnodelinks[MAX_NODELINKS];
void CS_TouchLinks ( csqcedict_t *ent, areanode_t *node )
{ //Spike: rewritten this function to cope with killtargets used on a few maps.
link_t *l, *next;
csqcedict_t *touch;
int old_self, old_other;
int linkcount = 0, ln;
//work out who they are first.
for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)
{
if (linkcount == MAX_NODELINKS)
break;
next = l->next;
touch = CSEDICT_FROM_AREA(l);
if (touch == ent)
continue;
if (!touch->v->touch || touch->v->solid != SOLID_TRIGGER)
continue;
if (ent->v->absmin[0] > touch->v->absmax[0]
|| ent->v->absmin[1] > touch->v->absmax[1]
|| ent->v->absmin[2] > touch->v->absmax[2]
|| ent->v->absmax[0] < touch->v->absmin[0]
|| ent->v->absmax[1] < touch->v->absmin[1]
|| ent->v->absmax[2] < touch->v->absmin[2] )
continue;
// if (!((int)ent->xv->dimension_solid & (int)touch->xv->dimension_hit))
// continue;
csnodelinks[linkcount++] = touch;
}
old_self = *csqcg.self;
old_other = *csqcg.other;
for (ln = 0; ln < linkcount; ln++)
{
touch = csnodelinks[ln];
//make sure nothing moved it away
if (touch->isfree)
continue;
if (!touch->v->touch || touch->v->solid != SOLID_TRIGGER)
continue;
if (ent->v->absmin[0] > touch->v->absmax[0]
|| ent->v->absmin[1] > touch->v->absmax[1]
|| ent->v->absmin[2] > touch->v->absmax[2]
|| ent->v->absmax[0] < touch->v->absmin[0]
|| ent->v->absmax[1] < touch->v->absmin[1]
|| ent->v->absmax[2] < touch->v->absmin[2] )
continue;
// if (!((int)ent->xv->dimension_solid & (int)touch->xv->dimension_hit)) //didn't change did it?...
// continue;
*csqcg.self = EDICT_TO_PROG(csqcprogs, (edict_t*)touch);
*csqcg.other = EDICT_TO_PROG(csqcprogs, (edict_t*)ent);
PR_ExecuteProgram (csqcprogs, touch->v->touch);
if (ent->isfree)
break;
}
*csqcg.self = old_self;
*csqcg.other = old_other;
// recurse down both sides
if (node->axis == -1 || ent->isfree)
return;
if ( ent->v->absmax[node->axis] > node->dist )
CS_TouchLinks ( ent, node->children[0] );
if ( ent->v->absmin[node->axis] < node->dist )
CS_TouchLinks ( ent, node->children[1] );
}
static void CS_UnlinkEdict (csqcedict_t *ent)
{
if (!ent->area.prev)
return; // not linked in anywhere
RemoveLink (&ent->area);
ent->area.prev = ent->area.next = NULL;
}
static void CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers)
{
areanode_t *node;
if (ent->area.prev)
CS_UnlinkEdict (ent); // unlink from old position
if (ent == csqc_edicts)
return; // don't add the world
//FIXME: use some sort of area grid ?
VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmin);
VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmax);
if ((int)ent->v->flags & FL_ITEM)
{
ent->v->absmin[0] -= 15;
ent->v->absmin[1] -= 15;
ent->v->absmax[0] += 15;
ent->v->absmax[1] += 15;
}
else
{ // because movement is clipped an epsilon away from an actual edge,
// we must fully check even when bounding boxes don't quite touch
ent->v->absmin[0] -= 1;
ent->v->absmin[1] -= 1;
ent->v->absmin[2] -= 1;
ent->v->absmax[0] += 1;
ent->v->absmax[1] += 1;
ent->v->absmax[2] += 1;
}
if (!ent->v->solid)
return;
// find the first node that the ent's box crosses
node = cs_areanodes;
while (1)
{
if (node->axis == -1)
break;
if (ent->v->absmin[node->axis] > node->dist)
node = node->children[0];
else if (ent->v->absmax[node->axis] < node->dist)
node = node->children[1];
else
break; // crosses the node
}
// link it in
if (ent->v->solid == SOLID_TRIGGER)
InsertLinkBefore(&ent->area, &node->trigger_edicts);
else
InsertLinkBefore(&ent->area, &node->solid_edicts);
// if touch_triggers, touch all entities at this node and decend for more
if (touchtriggers)
CS_TouchLinks(ent, cs_areanodes);
}
typedef struct {
int type;
trace_t trace;
vec3_t boxmins; //mins/max of total move.
vec3_t boxmaxs;
vec3_t start;
vec3_t end;
vec3_t mins; //mins/max of ent
vec3_t maxs;
csqcedict_t *passedict;
} moveclip_t;
#define CSEDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,csqcedict_t,area)
static void CS_ClipToLinks ( areanode_t *node, moveclip_t *clip )
{
model_t *model;
trace_t tr;
link_t *l, *next;
csqcedict_t *touch;
//work out who they are first.
for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
{
next = l->next;
touch = (csqcedict_t*)CSEDICT_FROM_AREA(l);
if (touch->v->solid == SOLID_NOT)
continue;
if (touch == clip->passedict)
continue;
if (touch->v->solid == SOLID_TRIGGER || touch->v->solid == SOLID_LADDER)
continue;
if (clip->type & MOVE_NOMONSTERS && touch->v->solid != SOLID_BSP)
continue;
if (clip->passedict)
{
// don't clip corpse against character
if (clip->passedict->v->solid == SOLID_CORPSE && (touch->v->solid == SOLID_SLIDEBOX || touch->v->solid == SOLID_CORPSE))
continue;
// don't clip character against corpse
if (clip->passedict->v->solid == SOLID_SLIDEBOX && touch->v->solid == SOLID_CORPSE)
continue;
if (!((int)clip->passedict->xv->dimension_hit & (int)touch->xv->dimension_solid))
continue;
}
if (clip->boxmins[0] > touch->v->absmax[0]
|| clip->boxmins[1] > touch->v->absmax[1]
|| clip->boxmins[2] > touch->v->absmax[2]
|| clip->boxmaxs[0] < touch->v->absmin[0]
|| clip->boxmaxs[1] < touch->v->absmin[1]
|| clip->boxmaxs[2] < touch->v->absmin[2] )
continue;
if (clip->passedict && clip->passedict->v->size[0] && !touch->v->size[0])
continue; // points never interact
// might intersect, so do an exact clip
if (clip->trace.allsolid)
return;
if (clip->passedict)
{
if ((csqcedict_t*)PROG_TO_EDICT(csqcprogs, touch->v->owner) == clip->passedict)
continue; // don't clip against own missiles
if ((csqcedict_t*)PROG_TO_EDICT(csqcprogs, clip->passedict->v->owner) == touch)
continue; // don't clip against owner
}
if (!((int)clip->passedict->xv->dimension_solid & (int)touch->xv->dimension_hit))
continue;
model = CSQC_GetModelForIndex(touch->v->modelindex);
if (!model)
continue;
model->funcs.Trace(model, 0, 0, clip->start, clip->end, clip->mins, clip->maxs, &tr);
if (tr.fraction < clip->trace.fraction)
{
tr.ent = (void*)touch;
clip->trace = tr;
}
}
}
static trace_t CS_Move(vec3_t v1, vec3_t mins, vec3_t maxs, vec3_t v2, float nomonsters, csqcedict_t *passedict)
{
moveclip_t clip;
if (cl.worldmodel)
{
cl.worldmodel->funcs.Trace(cl.worldmodel, 0, 0, v1, v2, mins, maxs, &clip.trace);
clip.trace.ent = (void*)csqc_edicts;
}
else
{
memset(&clip.trace, 0, sizeof(clip.trace));
clip.trace.fraction = 1;
VectorCopy(v2, clip.trace.endpos);
clip.trace.ent = (void*)csqc_edicts;
}
//why use trace.endpos instead?
//so that if we hit a wall early, we don't have a box covering the whole world because of a shotgun trace.
clip.boxmins[0] = ((v1[0] < clip.trace.endpos[0])?v1[0]:clip.trace.endpos[0]) - mins[0]-1;
clip.boxmins[1] = ((v1[1] < clip.trace.endpos[1])?v1[1]:clip.trace.endpos[1]) - mins[1]-1;
clip.boxmins[2] = ((v1[2] < clip.trace.endpos[2])?v1[2]:clip.trace.endpos[2]) - mins[2]-1;
clip.boxmaxs[0] = ((v1[0] > clip.trace.endpos[0])?v1[0]:clip.trace.endpos[0]) + maxs[0]+1;
clip.boxmaxs[1] = ((v1[1] > clip.trace.endpos[1])?v1[1]:clip.trace.endpos[1]) + maxs[1]+1;
clip.boxmaxs[2] = ((v1[2] > clip.trace.endpos[2])?v1[2]:clip.trace.endpos[2]) + maxs[2]+1;
VectorCopy(mins, clip.mins);
VectorCopy(maxs, clip.maxs);
VectorCopy(v1, clip.start);
VectorCopy(v2, clip.end);
clip.passedict = passedict;
CS_ClipToLinks(cs_areanodes, &clip);
return clip.trace;
}
static void CS_CheckVelocity(csqcedict_t *ent)
{
@ -872,7 +533,7 @@ static void PF_cs_remove (progfuncs_t *prinst, struct globalvars_s *pr_globals)
}
pe->DelinkTrailstate(&ed->trailstate);
CS_UnlinkEdict(ed);
World_UnlinkEdict((wedict_t*)ed);
ED_Free (prinst, (void*)ed);
}
@ -1114,26 +775,6 @@ static void PF_R_AddEntity(progfuncs_t *prinst, struct globalvars_s *pr_globals)
if (CopyCSQCEdictToEntity(in, &ent))
V_AddAxisEntity(&ent);
/*
{
float a[4];
float q[4];
float r[4];
EularToQuaternian(ent.angles, a);
QuaternainToAngleMatrix(a, ent.axis);
ent.origin[0] += 16;
V_AddEntity(&ent);
quaternion_rotation(0, 0, 1, cl.time*360, r);
quaternion_multiply(a, r, q);
QuaternainToAngleMatrix(q, ent.axis);
ent.origin[0] -= 32;
ent.angles[1] = cl.time;
V_AddEntity(&ent);
}
*/
}
static void PF_R_DynamicLight_Set(progfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -1234,7 +875,7 @@ static void PF_R_AddEntityMask(progfuncs_t *prinst, struct globalvars_s *pr_glob
*csqcg.self = EDICT_TO_PROG(prinst, (void*)ent);
PR_ExecuteProgram(prinst, ent->xv->predraw);
if (ent->isfree)
if (ent->isfree || (int)ent->xv->renderflags & CSQCRF_NOAUTOADD)
continue; //bummer...
}
@ -1815,7 +1456,7 @@ static void PF_cs_SetOrigin(progfuncs_t *prinst, struct globalvars_s *pr_globals
VectorCopy(org, ent->v->origin);
CS_LinkEdict(ent, false);
World_LinkEdict(&csqc_world, (wedict_t*)ent, false);
}
static void PF_cs_SetSize(progfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -1827,7 +1468,7 @@ static void PF_cs_SetSize(progfuncs_t *prinst, struct globalvars_s *pr_globals)
VectorCopy(mins, ent->v->mins);
VectorCopy(maxs, ent->v->maxs);
CS_LinkEdict(ent, false);
World_LinkEdict(&csqc_world, (wedict_t*)ent, false);
}
static void cs_settracevars(trace_t *tr)
@ -1847,7 +1488,7 @@ static void cs_settracevars(trace_t *tr)
if (tr->ent)
*csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)tr->ent);
else
*csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)csqc_edicts);
*csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)csqc_world.edicts);
}
static void PF_cs_traceline(progfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -1876,7 +1517,7 @@ static void PF_cs_traceline(progfuncs_t *prinst, struct globalvars_s *pr_globals
savedhull = ent->xv->hull;
ent->xv->hull = 0;
trace = CS_Move (v1, mins, maxs, v2, nomonsters, ent);
trace = World_Move (&csqc_world, v1, mins, maxs, v2, nomonsters, (wedict_t*)ent);
ent->xv->hull = savedhull;
cs_settracevars(&trace);
@ -1898,7 +1539,7 @@ static void PF_cs_tracebox(progfuncs_t *prinst, struct globalvars_s *pr_globals)
savedhull = ent->xv->hull;
ent->xv->hull = 0;
trace = CS_Move (v1, mins, maxs, v2, nomonsters, ent);
trace = World_Move (&csqc_world, v1, mins, maxs, v2, nomonsters, (wedict_t*)ent);
ent->xv->hull = savedhull;
*csqcg.trace_allsolid = trace.allsolid;
@ -1912,7 +1553,7 @@ static void PF_cs_tracebox(progfuncs_t *prinst, struct globalvars_s *pr_globals)
if (trace.ent)
*csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)trace.ent);
else
*csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)csqc_edicts);
*csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)csqc_world.edicts);
}
static trace_t CS_Trace_Toss (csqcedict_t *tossent, csqcedict_t *ignore)
@ -1944,7 +1585,7 @@ static trace_t CS_Trace_Toss (csqcedict_t *tossent, csqcedict_t *ignore)
velocity[2] -= gravity;
VectorScale (velocity, 0.05, move);
VectorAdd (origin, move, end);
trace = CS_Move (origin, tossent->v->mins, tossent->v->maxs, end, MOVE_NORMAL, tossent);
trace = World_Move (&csqc_world, origin, tossent->v->mins, tossent->v->maxs, end, MOVE_NORMAL, (wedict_t*)tossent);
VectorCopy (trace.endpos, origin);
CS_CheckVelocity (tossent);
@ -1964,7 +1605,7 @@ static void PF_cs_tracetoss (progfuncs_t *prinst, struct globalvars_s *pr_global
csqcedict_t *ignore;
ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0);
if (ent == csqc_edicts)
if (ent == (csqcedict_t*)csqc_world.edicts)
Con_DPrintf("tracetoss: can not use world entity\n");
ignore = (csqcedict_t*)G_EDICT(prinst, OFS_PARM1);
@ -1981,7 +1622,7 @@ static void PF_cs_tracetoss (progfuncs_t *prinst, struct globalvars_s *pr_global
if (trace.ent)
*csqcg.trace_ent = EDICT_TO_PROG(prinst, trace.ent);
else
*csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)csqc_edicts);
*csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)csqc_world.edicts);
}
static int CS_PointContents(vec3_t org)
@ -2071,7 +1712,7 @@ static void csqc_setmodel(progfuncs_t *prinst, csqcedict_t *ent, int modelindex)
VectorClear(ent->v->maxs);
}
CS_LinkEdict(ent, false);
World_LinkEdict(&csqc_world, (wedict_t*)ent, false);
}
static void PF_cs_SetModel(progfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -2568,7 +2209,7 @@ typedef struct {
//fixme: touch solids
CS_LinkEdict (ent, true);
World_LinkEdict (&csqc_world, (wedict_t*)ent, true);
}
static void PF_cs_getentitytoken (progfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -3540,14 +3181,14 @@ static void PF_cs_droptofloor (progfuncs_t *prinst, struct globalvars_s *pr_glob
end[2] -= 512;
VectorCopy (ent->v->origin, start);
trace = CS_Move (start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
trace = World_Move (&csqc_world, start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, (wedict_t*)ent);
if (trace.fraction == 1 || trace.allsolid)
G_FLOAT(OFS_RETURN) = 0;
else
{
VectorCopy (trace.endpos, ent->v->origin);
CS_LinkEdict (ent, false);
World_LinkEdict(&csqc_world, (wedict_t*)ent, false);
ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
ent->v->groundentity = EDICT_TO_PROG(prinst, trace.ent);
G_FLOAT(OFS_RETURN) = 1;
@ -3563,7 +3204,7 @@ static void PF_cs_copyentity (progfuncs_t *prinst, struct globalvars_s *pr_globa
memcpy(out->v, in->v, csqcentsize);
CS_LinkEdict (out, false);
World_LinkEdict (&csqc_world, (wedict_t*)out, false);
}
static void PF_cl_playingdemo (progfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4335,7 +3976,7 @@ realcheck:
start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
stop[2] = start[2] - 2*movevars.stepheight;
trace = CS_Move (start, vec3_origin, vec3_origin, stop, true, ent);
trace = World_Move (&csqc_world, start, vec3_origin, vec3_origin, stop, true, (wedict_t*)ent);
if (trace.fraction == 1.0)
return false;
@ -4350,7 +3991,7 @@ realcheck:
savedhull = ent->xv->hull;
ent->xv->hull = 0;
trace = CS_Move (start, vec3_origin, vec3_origin, stop, true, ent);
trace = World_Move (&csqc_world, start, vec3_origin, vec3_origin, stop, true, (wedict_t*)ent);
ent->xv->hull = savedhull;
if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
@ -4385,7 +4026,7 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
vec3_t oldorg, neworg, end;
trace_t trace;
int i;
csqcedict_t *enemy = csqc_edicts;
csqcedict_t *enemy = (csqcedict_t*)csqc_world.edicts;
// try the move
VectorCopy (ent->v->origin, oldorg);
@ -4401,7 +4042,7 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
if (!noenemy)
{
enemy = (csqcedict_t*)PROG_TO_EDICT(csqcprogs, ent->v->enemy);
if (i == 0 && enemy != csqc_edicts)
if (i == 0 && enemy != (csqcedict_t*)csqc_world.edicts)
{
dz = ent->v->origin[2] - ((csqcedict_t*)PROG_TO_EDICT(csqcprogs, ent->v->enemy))->v->origin[2];
if (dz > 40)
@ -4410,7 +4051,7 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
neworg[2] += 8;
}
}
trace = CS_Move (ent->v->origin, ent->v->mins, ent->v->maxs, neworg, false, ent);
trace = World_Move (&csqc_world, ent->v->origin, ent->v->mins, ent->v->maxs, neworg, false, (wedict_t*)ent);
if (set_trace)
cs_settracevars(&trace);
@ -4421,11 +4062,11 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
VectorCopy (trace.endpos, ent->v->origin);
if (relink)
CS_LinkEdict (ent, true);
World_LinkEdict (&csqc_world, (wedict_t*)ent, true);
return true;
}
if (noenemy || enemy == csqc_edicts)
if (noenemy || enemy == (csqcedict_t*)csqc_world.edicts)
break;
}
@ -4437,7 +4078,7 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
VectorCopy (neworg, end);
end[2] -= movevars.stepheight*2;
trace = CS_Move (neworg, ent->v->mins, ent->v->maxs, end, false, ent);
trace = World_Move (&csqc_world, neworg, ent->v->mins, ent->v->maxs, end, false, (wedict_t*)ent);
if (set_trace)
cs_settracevars(&trace);
@ -4447,7 +4088,7 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
if (trace.startsolid)
{
neworg[2] -= movevars.stepheight;
trace = CS_Move (neworg, ent->v->mins, ent->v->maxs, end, false, ent);
trace = World_Move (&csqc_world, neworg, ent->v->mins, ent->v->maxs, end, false, (wedict_t*)ent);
if (set_trace)
cs_settracevars(&trace);
if (trace.allsolid || trace.startsolid)
@ -4460,7 +4101,7 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
{
VectorAdd (ent->v->origin, move, ent->v->origin);
if (relink)
CS_LinkEdict (ent, true);
World_LinkEdict (&csqc_world, (wedict_t*)ent, true);
ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
// Con_Printf ("fall down\n");
return true;
@ -4478,7 +4119,7 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
{ // entity had floor mostly pulled out from underneath it
// and is trying to correct
if (relink)
CS_LinkEdict (ent, true);
World_LinkEdict (&csqc_world, (wedict_t*)ent, true);
return true;
}
VectorCopy (oldorg, ent->v->origin);
@ -4494,7 +4135,7 @@ static qboolean CS_movestep (csqcedict_t *ent, vec3_t move, qboolean relink, qbo
// the move is ok
if (relink)
CS_LinkEdict (ent, true);
World_LinkEdict (&csqc_world, (wedict_t*)ent, true);
return true;
}
@ -5640,6 +5281,25 @@ pbool CSQC_EntFree (struct edict_s *e)
return true;
}
void CSQC_Event_Touch(world_t *w, wedict_t *s, wedict_t *o)
{
int oself = *csqcg.self;
int oother = *csqcg.other;
*csqcg.self = EDICT_TO_PROG(w->progs, (edict_t*)s);
*csqcg.other = EDICT_TO_PROG(w->progs, (edict_t*)o);
PR_ExecuteProgram (w->progs, s->v->touch);
*csqcg.self = oself;
*csqcg.other = oother;
}
model_t *CSQC_World_ModelForIndex(world_t *w, int modelindex)
{
return CSQC_GetModelForIndex(modelindex);
}
void CSQC_Shutdown(void)
{
search_close_progs(csqcprogs, false);
@ -5663,7 +5323,7 @@ void CSQC_Shutdown(void)
csqcmapentitydataloaded = false;
in_sensitivityscale = 1;
num_csqc_edicts = 0;
csqc_world.num_edicts = 0;
csqc_usinglistener = false;
}
@ -5842,8 +5502,8 @@ qboolean CSQC_Init (unsigned int checksum)
csqcprogparms.gametime = &csqctime;
csqcprogparms.sv_edicts = (struct edict_s **)&csqc_edicts;
csqcprogparms.sv_num_edicts = &num_csqc_edicts;
csqcprogparms.sv_edicts = (struct edict_s **)&csqc_world.edicts;
csqcprogparms.sv_num_edicts = &csqc_world.num_edicts;
csqcprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms);
@ -5854,8 +5514,10 @@ qboolean CSQC_Init (unsigned int checksum)
csqcmapentitydataloaded = true;
csqcprogs = InitProgs(&csqcprogparms);
PR_Configure(csqcprogs, -1, 16);
CS_ClearWorld();
csqc_world.worldmodel = cl.worldmodel;
csqc_world.Event_Touch = CSQC_Event_Touch;
csqc_world.GetCModel = CSQC_World_ModelForIndex;
World_ClearWorld(&csqc_world);
CSQC_InitFields(); //let the qclib know the field order that the engine needs.
csqc_isdarkplaces = false;
@ -6092,6 +5754,7 @@ qboolean CSQC_DrawView(void)
r_secondaryview = 0;
CL_CalcClientTime();
csqc_world.physicstime = cl.servertime;
DropPunchAngle (0);
if (cl.worldmodel)
@ -6108,12 +5771,6 @@ qboolean CSQC_DrawView(void)
CSQC_ChangeLocalPlayer(0);
/* if (csqcg.dpcompat_sbshowscores)
{
extern qboolean sb_showscores;
*csqcg.dpcompat_sbshowscores = sb_showscores;
}
*/
if (csqcg.cltime)
*csqcg.cltime = cl.time;
if (csqcg.svtime)

View File

@ -358,7 +358,7 @@ void PF_CL_drawcharacter (progfuncs_t *prinst, struct globalvars_s *pr_globals)
#pragma message("fixme: this doesn't scale or colour chars")
Font_BeginString(font_conchar, pos[0], pos[1], &x, &y);
Font_ForceColour(rgb[0], rgb[1], rgb[2], alpha);
Font_DrawChar(x, y, 0xe000|(chara&0xff));
Font_DrawChar(x, y, CON_WHITEMASK | 0xe000|(chara&0xff));
Font_ForceColour(1, 1, 1, 1);
Font_EndString(font_conchar);
@ -460,6 +460,8 @@ void PF_CL_drawpic (progfuncs_t *prinst, struct globalvars_s *pr_globals)
mpic_t *p;
p = Draw_SafeCachePic(picname);
if (!p)
p = Draw_SafePicFromWad(picname);
PF_SelectDPDrawFlag(flag);
Draw_ImageColours(rgb[0], rgb[1], rgb[2], alpha);

View File

@ -268,7 +268,6 @@ extern qboolean isDedicated;
void FTE_DEPRECATED GL_DrawAliasMesh (mesh_t *mesh, texid_t texnum);
void FTE_DEPRECATED R_RenderMeshBuffer(struct meshbuffer_s *mb, qboolean shadowpass);

2724
engine/client/r_surf.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -176,6 +176,52 @@ extern struct texture_s *r_notexture_mip;
extern entity_t r_worldentity;
//gl_alias.c
void R_DrawGAliasModel (entity_t *e, unsigned int rmode);
//r_surf.c
struct model_s;
struct msurface_s;
void Surf_DrawWorld(void);
void Surf_StainSurf(struct msurface_s *surf, float *parms);
void Surf_AddStain(vec3_t org, float red, float green, float blue, float radius);
void Surf_LessenStains(void);
void Surf_WipeStains(void);
void Surf_DeInit(void);
void Surf_BuildLightmaps(void);
void Surf_RenderDynamicLightmaps (struct msurface_s *fa, int shift);
int Surf_LightmapShift (struct model_s *model);
#ifndef LMBLOCK_WIDTH
#define LMBLOCK_WIDTH 128
#define LMBLOCK_HEIGHT 128
typedef struct glRect_s {
unsigned char l,t,w,h;
} glRect_t;
typedef unsigned char stmap;
struct mesh_s;
typedef struct {
struct mesh_s *meshchain;
qboolean modified;
qboolean deluxmodified;
glRect_t rectchange;
glRect_t deluxrectchange;
int allocated[LMBLOCK_WIDTH];
qbyte lightmaps[4*LMBLOCK_WIDTH*LMBLOCK_HEIGHT];
qbyte deluxmaps[4*LMBLOCK_WIDTH*LMBLOCK_HEIGHT]; //fixme: make seperate structure for easy disabling with less memory usage.
stmap stainmaps[3*LMBLOCK_WIDTH*LMBLOCK_HEIGHT]; //rgb no a. added to lightmap for added (hopefully) speed.
} lightmapinfo_t;
extern lightmapinfo_t **lightmap;
extern int numlightmaps;
extern texid_t *lightmap_textures;
extern texid_t *deluxmap_textures;
extern int lightmap_bytes; // 1, 3(, or 4)
#endif
#if defined(GLQUAKE)
void GLR_Init (void);
void GLR_ReInit (void);
@ -193,9 +239,6 @@ void GLR_NewMap (void);
void GLR_PushDlights (void);
void GLR_DrawWaterSurfaces (void);
void GLR_AddStain(vec3_t org, float red, float green, float blue, float radius);
void GLR_LessenStains(void);
void MediaGL_ShowFrame8bit(qbyte *framedata, int inwidth, int inheight, qbyte *palette);
void MediaGL_ShowFrameRGBA_32(qbyte *framedata, int inwidth, int inheight); //top down
void MediaGL_ShowFrameBGR_24_Flip(qbyte *framedata, int inwidth, int inheight); //input is bottom up...
@ -241,65 +284,7 @@ enum uploadfmt
};
#if 0
/*
int R_LoadTexture(char *name, int width, int height, void *data, void *palette, int flags)
{
if (palette)
{
if (flags & TF_BUMPMAP)
return 0; //huh?
if (flags & TF_FULLBRIGHT)
return 0; //huh?
if (flags & TF_32BIT)
return R_LoadTexture8Pal32(name, width, height, data, palette, flags&TF_MIPMAP, flags&TF_ALPHA);
return 0;
}
if (flags & TF_FULLBRIGHT)
{
if (flags & TF_BUMPMAP)
return 0; //huh?
if (flags & TF_24BIT)
return 0;
if (flags & TF_32BIT)
return 0;
//8bit fullbrights
return R_LoadTextureFB(name, width, height, data, flags&TF_MIPMAP, flags&TF_ALPHA);
}
if (flags & TF_BUMPMAP)
{
if (flags & TF_24BIT)
return 0;
if (flags & TF_32BIT)
return R_LoadTexture32(name, width, height, data, flags&TF_MIPMAP, flags&TF_ALPHA); //Warning: this is not correct
return R_LoadTexture8Bump(skinname,width,height,data,usemips,alpha) R_LoadTexture(name, width, height, data, NULL, TF_BUMPMAP | ((usemips)?TF_MIPMAP:TF_NOMIPMAP) | ((alpha)?TF_ALPHA:TF_NOALPHA))
}
if (flags & TF_32BIT)
return R_LoadTexture32(name, width, height, data, flags&TF_MIPMAP, flags&TF_ALPHA);
if (data)
return R_LoadTexture8(name, width, height, data, flags&TF_MIPMAP, flags&TF_ALPHA);
return R_FindTexture(name);
}
#define R_LoadTexture8Pal32(skinname,width,height,data,palette,usemips,alpha) R_LoadTexture(name, width, height, data, palette, TF_32BIT | ((usemips)?TF_MIPMAP:TF_NOMIPMAP) | ((alpha)?TF_ALPHA:TF_NOALPHA))
#define R_LoadTexture8(skinname,width,height,data,usemips,alpha) R_LoadTexture(name, width, height, data, NULL, ((usemips)?TF_MIPMAP:TF_NOMIPMAP) | ((alpha)?TF_ALPHA:TF_NOALPHA))
#define R_LoadTexture32(skinname,width,height,data,usemips,alpha) R_LoadTexture(name, width, height, data, NULL, TF_32BIT | ((usemips)?TF_MIPMAP:TF_NOMIPMAP) | ((alpha)?TF_ALPHA:TF_NOALPHA))
#define R_LoadTextureFB(skinname,width,height,data,usemips,alpha) R_LoadTexture(name, width, height, data, NULL, TF_FULLBRIGHT | ((usemips)?TF_MIPMAP:TF_NOMIPMAP) | ((alpha)?TF_ALPHA:TF_NOALPHA))
#define R_LoadTexture8Bump(skinname,width,height,data,usemips,alpha) R_LoadTexture(name, width, height, data, NULL, TF_BUMPMAP | ((usemips)?TF_MIPMAP:TF_NOMIPMAP) | ((alpha)?TF_ALPHA:TF_NOALPHA))
#define R_FindTexture(name) R_LoadTexture(name, 0, 0, NULL, NULL, 0)
#define R_LoadCompressed(name) ((qrenderer == QR_OPENGL)?GL_LoadCompressed(name):0)
*/
#elif defined(GLQUAKE) && defined(D3DQUAKE)
#if defined(GLQUAKE) && defined(D3DQUAKE)
#define R_LoadTexture8Pal32(skinname,width,height,data,palette,usemips,alpha) ((qrenderer == QR_DIRECT3D)?D3D_LoadTexture8Pal32(skinname, width, height, data, palette, usemips, alpha):GL_LoadTexture8Pal32(skinname, width, height, data, palette, usemips, alpha))
#define R_LoadTexture8Pal24(skinname,width,height,data,palette,usemips,alpha) ((qrenderer == QR_DIRECT3D)?D3D_LoadTexture8Pal24(skinname, width, height, data, palette, usemips, alpha):GL_LoadTexture8Pal24(skinname, width, height, data, palette, usemips, alpha))
@ -362,6 +347,8 @@ extern texid_t balltexture;
extern texid_t beamtexture;
extern texid_t ptritexture;
extern float r_projection_matrix[16];
extern float r_view_matrix[16];
void GL_ParallelPerspective(double xmin, double xmax, double ymax, double ymin, double znear, double zfar);
void GL_InfinatePerspective(double fovx, double fovy, double zNear);
@ -383,7 +370,6 @@ struct mleaf_s *RMod_PointInLeaf (struct model_s *model, float *p);
void RMod_Think (void);
void RMod_NowLoadExternal(void);
void GLR_WipeStains(void);
void GLR_LoadSkys (void);
void R_BloomRegister(void);
#endif
@ -411,6 +397,7 @@ qbyte *R_MarkLeaves_Q3 (void);
void R_SetFrustum (float projmat[16], float viewmat[16]);
void R_SetRenderer(int wanted);
void R_AnimateLight (void);
struct texture_s *R_TextureAnimation (struct texture_s *base);
void RQ_Init(void);
void CLQ2_EntityEvent(entity_state_t *es);

View File

@ -1445,9 +1445,9 @@ TRACE(("dbg: R_ApplyRenderer: clearing world\n"));
for (i = 0; i < MAX_MODELS; i++)
{
if (sv.strings.model_precache[i] && *sv.strings.model_precache[i] && (!strcmp(sv.strings.model_precache[i] + strlen(sv.strings.model_precache[i]) - 4, ".bsp") || i-1 < sv.world.worldmodel->numsubmodels))
sv.world.models[i] = Mod_FindName(sv.strings.model_precache[i]);
sv.models[i] = Mod_FindName(sv.strings.model_precache[i]);
else
sv.world.models[i] = NULL;
sv.models[i] = NULL;
}
ent = sv.world.edicts;
@ -1473,9 +1473,9 @@ TRACE(("dbg: R_ApplyRenderer: clearing world\n"));
for (i = 0; i < MAX_MODELS; i++)
{
if (sv.strings.configstring[Q2CS_MODELS+i] && *sv.strings.configstring[Q2CS_MODELS+i] && (!strcmp(sv.strings.configstring[Q2CS_MODELS+i] + strlen(sv.strings.configstring[Q2CS_MODELS+i]) - 4, ".bsp") || i-1 < sv.world.worldmodel->numsubmodels))
sv.world.models[i] = Mod_FindName(sv.strings.configstring[Q2CS_MODELS+i]);
sv.models[i] = Mod_FindName(sv.strings.configstring[Q2CS_MODELS+i]);
else
sv.world.models[i] = NULL;
sv.models[i] = NULL;
}
q2ent = ge->edicts;

View File

@ -63,8 +63,6 @@ FTE_DEPRECATED unsigned conheight;
unsigned pixelwidth;
unsigned pixelheight;
float pixeloffset; //Add this to the 1:1 vertex coord to place quads and stuff in the right places.
} viddef_t;
extern viddef_t vid; // global video state

View File

@ -30,8 +30,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef USEODE
#pragma message("fixme: fix this up before adding to csqc")
//#define pr_global_struct dgsdfg sdfg sdfg sd gsgd
#pragma message("fixme: pitch values are probably inverted")
//============================================================================
@ -1689,25 +1687,13 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
movetype = (int)ed->v->movetype;
scale = ed->xv->scale;
modelindex = 0;
model = NULL;
switch(solid)
{
case SOLID_BSP:
modelindex = (int)ed->v->modelindex;
if (modelindex >= 1 && modelindex < MAX_MODELS)
{
model = world->models[modelindex];
}
#pragma message("no csqc models")
/* else if (world == &cl.world && modelindex <= -1 && modelindex > MAX_MODELS)
{
model = cl.model_precache[modelindex];
}*/
else
{
model = NULL;
modelindex = 0;
}
model = world->GetCModel(world, modelindex);
if (model)
{
VectorScale(model->mins, scale, entmins);
@ -1726,13 +1712,11 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
case SOLID_PHYSICS_BOX:
case SOLID_PHYSICS_SPHERE:
case SOLID_PHYSICS_CAPSULE:
model = NULL;
VectorCopy(ed->v->mins, entmins);
VectorCopy(ed->v->maxs, entmaxs);
massval = ed->xv->mass;
break;
default:
model = NULL;
if (ed->ode.ode_physics)
World_Physics_RemoveFromEntity(world, ed);
return;
@ -2119,27 +2103,11 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2)
if(ed1 && ed1->v->touch)
{
pr_global_struct->self = EDICT_TO_PROG(world->progs, ed1);
pr_global_struct->other = EDICT_TO_PROG(world->progs, (edict_t*)(ed2 ? ed2 : world->edicts));
pr_global_struct->time = world->physicstime;
#ifdef VM_Q1
if (world==&sv.world && svs.gametype == GT_Q1QVM)
Q1QVM_Touch();
else
#endif
PR_ExecuteProgram (world->progs, ed1->v->touch);
world->Event_Touch(world, ed1, ed2);
}
if(ed2 && ed2->v->touch)
{
pr_global_struct->self = EDICT_TO_PROG(world->progs, ed2);
pr_global_struct->other = EDICT_TO_PROG(world->progs, (edict_t*)(ed1 ? ed1 : world->edicts));
pr_global_struct->time = world->physicstime;
#ifdef VM_Q1
if (world==&sv.world && svs.gametype == GT_Q1QVM)
Q1QVM_Touch();
else
#endif
PR_ExecuteProgram (world->progs, ed2->v->touch);
world->Event_Touch(world, ed2, ed1);
}
// merge bounce factors and bounce stop

View File

@ -3431,8 +3431,6 @@ void Q2BSP_MarkLights (dlight_t *light, int bit, mnode_t *node)
}
#ifndef SERVERONLY
#ifdef GLQUAKE
void GLR_StainSurf (msurface_t *surf, float *parms);
void GLR_Q2BSP_StainNode (mnode_t *node, float *parms)
{
mplane_t *splitplane;
@ -3463,14 +3461,13 @@ void GLR_Q2BSP_StainNode (mnode_t *node, float *parms)
{
if (surf->flags&~(SURF_DONTWARP|SURF_PLANEBACK))
continue;
GLR_StainSurf(surf, parms);
Surf_StainSurf(surf, parms);
}
GLR_Q2BSP_StainNode (node->children[0], parms);
GLR_Q2BSP_StainNode (node->children[1], parms);
}
#endif
#endif
#endif

View File

@ -1922,7 +1922,7 @@ void PF_bitshift(progfuncs_t *prinst, struct globalvars_s *pr_globals)
shift = G_FLOAT(OFS_PARM1);
if (shift < 0)
bitmask >>= shift;
bitmask >>= -shift;
else
bitmask <<= shift;
@ -2441,7 +2441,7 @@ lh_extension_t QSG_Extensions[] = {
{NULL},
//{"EXT_CSQC"}, //this is the base csqc extension. I'm not sure what needs to be separate and what does not.
//{"EXT_CSQC_DELTAS"},//this is a separate extension because a: its slower thus optional. b: the feature may be banned in a league due to cheat protection.
//{"EXT_CSQC_DELTAS"},//this is a separate extension because the feature may be banned in a league due to cheat protection.
//the rest are generic extensions
{"??TOMAZ_STRINGS", 6, NULL, {"tq_zone", "tq_unzone", "tq_strcat", "tq_substring", "tq_stof", "tq_stov"}},
@ -2573,7 +2573,9 @@ lh_extension_t QSG_Extensions[] = {
#endif
{"FTE_MULTIPROGS"}, //multiprogs functions are available.
{"FTE_MULTITHREADED", 3, NULL, {"sleep", "fork", "abort"}},
#ifdef SERVER_DEMO_PLAYBACK
{"FTE_MVD_PLAYBACK"},
#endif
#ifdef SVCHAT
{"FTE_NPCCHAT", 1, NULL, {"chat"}}, //server looks at chat files. It automagically branches through calling qc functions as requested.
#endif

View File

@ -328,6 +328,9 @@ void PF_Common_RegisterCvars(void);
/*these are server ones, provided by pr_cmds.c, as required by pr_q1qvm.c*/
#ifdef VM_Q1
model_t *SVPR_GetCModel(world_t *w, int modelindex);
void SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o);
void PF_WriteByte (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_WriteChar (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_WriteShort (progfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -360,7 +363,7 @@ char *PF_infokey_Internal (int entnum, char *value);
void PF_centerprint_Internal (int entnum, char *s);
void PF_WriteString_Internal (int target, char *str);
pbool ED_CanFree (edict_t *ed);
#endif
// edict->solid values

View File

@ -114,15 +114,17 @@ typedef struct
} laggedentinfo_t;
struct world_s {
void (*Event_Touch)(struct world_s *w, wedict_t *s, wedict_t *o);
model_t *(*GetCModel)(struct world_s *w, int modelindex);
unsigned int max_edicts; //limiting factor... 1024 fields*4*MAX_EDICTS == a heck of a lot.
unsigned int num_edicts; // increases towards MAX_EDICTS
unsigned int edict_size;
FTE_DEPRECATED unsigned int edict_size;
wedict_t *edicts; // can NOT be array indexed, because
// edict_t is variable sized, but can
// be used to reference the world ent
struct progfuncs_s *progs;
model_t *worldmodel;
struct model_s *models[MAX_MODELS];
areanode_t areanodes[AREA_NODES];
int numareanodes;

View File

@ -3,7 +3,17 @@
#include "shader.h"
#include <d3d9.h>
LPDIRECT3DDEVICE9 pD3DDev9;
extern LPDIRECT3DDEVICE9 pD3DDev9;
typedef struct
{
shader_t *curshader;
texnums_t *curtexnums;
texid_t curlightmap;
texid_t curdeluxmap;
} d3dbackend_t;
static d3dbackend_t d3dbackend;
extern int be_maxpasses;
@ -12,7 +22,7 @@ void BE_Init(void)
be_maxpasses = 1;
}
static D3DBE_ApplyShaderBits(unsigned int bits)
static void D3DBE_ApplyShaderBits(unsigned int bits)
{
if (bits & SBITS_BLEND_BITS)
{
@ -21,8 +31,8 @@ static D3DBE_ApplyShaderBits(unsigned int bits)
switch(bits & SBITS_SRCBLEND_BITS)
{
case SBITS_SRCBLEND_ZERO: dst = D3DBLEND_ZERO; break;
case SBITS_SRCBLEND_ONE: dst = D3DBLEND_ONE; break;
case SBITS_SRCBLEND_ZERO: src = D3DBLEND_ZERO; break;
case SBITS_SRCBLEND_ONE: src = D3DBLEND_ONE; break;
case SBITS_SRCBLEND_DST_COLOR: src = D3DBLEND_DESTCOLOR; break;
case SBITS_SRCBLEND_ONE_MINUS_DST_COLOR: src = D3DBLEND_INVDESTCOLOR; break;
case SBITS_SRCBLEND_SRC_ALPHA: src = D3DBLEND_SRCALPHA; break;
@ -30,6 +40,7 @@ static D3DBE_ApplyShaderBits(unsigned int bits)
case SBITS_SRCBLEND_DST_ALPHA: src = D3DBLEND_DESTALPHA; break;
case SBITS_SRCBLEND_ONE_MINUS_DST_ALPHA: src = D3DBLEND_INVDESTALPHA; break;
case SBITS_SRCBLEND_ALPHA_SATURATE: src = D3DBLEND_SRCALPHASAT; break;
default: Sys_Error("Bad shader blend src\n"); return;
}
switch(bits & SBITS_DSTBLEND_BITS)
{
@ -41,6 +52,7 @@ static D3DBE_ApplyShaderBits(unsigned int bits)
case SBITS_DSTBLEND_ONE_MINUS_DST_ALPHA: dst = D3DBLEND_INVDESTALPHA; break;
case SBITS_DSTBLEND_SRC_COLOR: dst = D3DBLEND_SRCCOLOR; break;
case SBITS_DSTBLEND_ONE_MINUS_SRC_COLOR: dst = D3DBLEND_INVSRCCOLOR; break;
default: Sys_Error("Bad shader blend dst\n"); return;
}
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHABLENDENABLE, TRUE);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRCBLEND, src);
@ -99,7 +111,7 @@ static D3DBE_ApplyShaderBits(unsigned int bits)
}
unsigned int workingbuffer[65536];
void BE_DrawMeshChain(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, texnums_t *texnums)
static void BE_DrawMeshChain_Internal(mesh_t *meshchain)
{
float *xyz;
unsigned int *colour;
@ -108,9 +120,9 @@ void BE_DrawMeshChain(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, texnums_t
unsigned int stride;
int i;
if (!shader)
if (!d3dbackend.curshader)
return;
if (!texnums)
if (!d3dbackend.curtexnums)
return;
stride = 0;
@ -127,35 +139,274 @@ memset(workingbuffer, 0, sizeof(workingbuffer));
stride += 2;
fmt |= D3DFVF_TEX1;
D3DBE_ApplyShaderBits(shader->passes[0].shaderbits);
D3DBE_ApplyShaderBits(d3dbackend.curshader->passes[0].shaderbits);
IDirect3DDevice9_SetFVF(pD3DDev9, fmt);
switch(shader->passes[0].texgen)
switch(d3dbackend.curshader->passes[0].texgen)
{
default:
case T_GEN_DIFFUSE:
IDirect3DDevice9_SetTexture (pD3DDev9, 0, texnums->base.ptr);
IDirect3DDevice9_SetTexture (pD3DDev9, 0, d3dbackend.curtexnums->base.ptr);
break;
case T_GEN_SINGLEMAP:
IDirect3DDevice9_SetTexture (pD3DDev9, 0, shader->passes[0].anim_frames[0].ptr);
IDirect3DDevice9_SetTexture (pD3DDev9, 0, d3dbackend.curshader->passes[0].anim_frames[0].ptr);
break;
}
switch(d3dbackend.curshader->passes[1].texgen)
{
case T_GEN_LIGHTMAP:
IDirect3DDevice9_SetTexture (pD3DDev9, 1, d3dbackend.curlightmap.ptr);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLORARG2, D3DTA_CURRENT);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
break;
default:
IDirect3DDevice9_SetTexture (pD3DDev9, 1, NULL);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
break;
}
/*I'm guessing I ought to create a temp vertex buffer for this*/
for (i = 0; i < meshchain->numvertexes; i++)
if (meshchain->colors4b_array)
{
VectorCopy(meshchain->xyz_array[i], (xyz+stride*i));
*(colour+stride*i) = 0xffffffff;//*(unsigned int*)meshchain->colors4b_array[i];
Vector2Copy(meshchain->st_array[i], (st[0]+stride*i));
/*I'm guessing I ought to create a temp vertex buffer for this*/
for (; meshchain; meshchain = meshchain->next)
{
for (i = 0; i < meshchain->numvertexes; i++)
{
VectorCopy(meshchain->xyz_array[i], (xyz+stride*i));
*(colour+stride*i) = ((unsigned int)meshchain->colors4b_array[i][3]<<24) | ((unsigned int)meshchain->colors4b_array[i][0]<<16) | ((unsigned int)meshchain->colors4b_array[i][1]<<8) | ((unsigned int)meshchain->colors4b_array[i][2]);
Vector2Copy(meshchain->st_array[i], (st[0]+stride*i));
}
IDirect3DDevice9_DrawIndexedPrimitiveUP(pD3DDev9, D3DPT_TRIANGLELIST, 0, meshchain->numvertexes, meshchain->numindexes/3, meshchain->indexes, D3DFMT_QINDEX, workingbuffer, stride*4);
}
}
IDirect3DDevice9_DrawIndexedPrimitiveUP(pD3DDev9, D3DPT_TRIANGLELIST, 0, meshchain->numvertexes, meshchain->numindexes/3, meshchain->indexes, D3DFMT_QINDEX, workingbuffer, stride*4);
else
{
/*I'm guessing I ought to create a temp vertex buffer for this*/
for (; meshchain; meshchain = meshchain->next)
{
for (i = 0; i < meshchain->numvertexes; i++)
{
VectorCopy(meshchain->xyz_array[i], (xyz+stride*i));
*(colour+stride*i) = 0xffffffff;//*(unsigned int*)meshchain->colors4b_array[i];
Vector2Copy(meshchain->st_array[i], (st[0]+stride*i));
}
IDirect3DDevice9_DrawIndexedPrimitiveUP(pD3DDev9, D3DPT_TRIANGLELIST, 0, meshchain->numvertexes, meshchain->numindexes/3, meshchain->indexes, D3DFMT_QINDEX, workingbuffer, stride*4);
}
}
}
void BE_DrawMeshChain(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, texnums_t *texnums)
{
d3dbackend.curshader = shader;
d3dbackend.curtexnums = texnums;
BE_DrawMeshChain_Internal(meshchain);
}
void BE_SelectMode(backendmode_t mode, unsigned int flags)
{
}
/*Generates an optimised vbo for each of the given model's textures*/
void BE_GenBrushModelVBO(model_t *mod)
{
}
/*Wipes a vbo*/
void BE_ClearVBO(vbo_t *vbo)
{
}
/*upload all lightmaps at the start to reduce lags*/
void BE_UploadAllLightmaps(void)
{
}
static void DrawSurfaceChain(msurface_t *s, shader_t *shader, vbo_t *vbo)
{ //doesn't merge surfaces, but tells gl to do each vertex arrayed surface individually, which means no vertex copying.
int i;
mesh_t *ml, *m;
if (!vbo)
return;
d3dbackend.curshader = shader;
d3dbackend.curtexnums = &shader->defaulttextures;
ml = NULL;
for (; s ; s=s->texturechain)
{
m = s->mesh;
if (!m) //urm.
continue;
if (m->numvertexes <= 1)
continue;
if (s->lightmaptexturenum < 0)
{
//pull out the surfaces with no lightmap info
m->next = ml;
ml = m;
}
else
{
//surfaces that do have a lightmap
m->next = lightmap[s->lightmaptexturenum]->meshchain;
lightmap[s->lightmaptexturenum]->meshchain = m;
}
}
if (ml)
{
//draw the lightmapless surfaces
BE_DrawMeshChain_Internal(ml);
}
//and then draw the lit chains
for (i = 0; i < numlightmaps; i++)
{
if (!lightmap[i] || !lightmap[i]->meshchain)
continue;
/*
if (lightmap[i]->modified)
{
glRect_t *theRect;
lightmap[i]->modified = false;
theRect = &lightmap[i]->rectchange;
GL_Bind(lightmap_textures[i]);
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
lightmap[i]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
theRect->l = LMBLOCK_WIDTH;
theRect->t = LMBLOCK_HEIGHT;
theRect->h = 0;
theRect->w = 0;
checkerror();
if (lightmap[i]->deluxmodified)
{
lightmap[i]->deluxmodified = false;
theRect = &lightmap[i]->deluxrectchange;
GL_Bind(deluxmap_textures[i]);
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE,
lightmap[i]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
theRect->l = LMBLOCK_WIDTH;
theRect->t = LMBLOCK_HEIGHT;
theRect->h = 0;
theRect->w = 0;
checkerror();
}
}
*/
d3dbackend.curlightmap = lightmap_textures[i];
d3dbackend.curdeluxmap = deluxmap_textures[i];
BE_DrawMeshChain_Internal(lightmap[i]->meshchain);
lightmap[i]->meshchain = NULL;
}
}
static void BE_BaseTextureChain(msurface_t *first)
{
texture_t *t, *tex;
shader_t *shader;
t = first->texinfo->texture;
tex = R_TextureAnimation (t);
//TEMP: use shader as an input parameter, not tex.
shader = tex->shader;
if (!shader)
{
shader = R_RegisterShader_Lightmap(tex->name);
tex->shader = shader;
}
DrawSurfaceChain(first, shader, &t->vbo);
}
void BE_BaseEntTextures(void)
{
extern model_t *currentmodel;
int i;
entity_t *ent;
if (!r_drawentities.ival)
return;
// draw sprites seperately, because of alpha blending
for (i=0 ; i<cl_numvisedicts ; i++)
{
ent = &cl_visedicts[i];
if (!ent->model)
continue;
if (ent->model->needload)
continue;
// if (!PPL_ShouldDraw())
// continue;
switch(ent->model->type)
{
case mod_brush:
// BaseBrushTextures(ent);
break;
case mod_alias:
R_DrawGAliasModel (ent, BEM_STANDARD);
break;
}
}
}
void BE_SubmitMeshes (void)
{
texture_t *t;
msurface_t *s;
int i;
model_t *model = cl.worldmodel;
unsigned int fl;
for (i=0 ; i<model->numtextures ; i++)
{
t = model->textures[i];
if (!t)
continue;
s = t->texturechain;
if (!s)
continue;
fl = s->texinfo->texture->shader->flags;
BE_BaseTextureChain(s);
}
BE_BaseEntTextures();
}
void BE_DrawWorld (qbyte *vis)
{
RSpeedLocals();
//make sure the world draws correctly
r_worldentity.shaderRGBAf[0] = 1;
r_worldentity.shaderRGBAf[1] = 1;
r_worldentity.shaderRGBAf[2] = 1;
r_worldentity.shaderRGBAf[3] = 1;
r_worldentity.axis[0][0] = 1;
r_worldentity.axis[1][1] = 1;
r_worldentity.axis[2][2] = 1;
BE_SelectMode(BEM_STANDARD, 0);
RSpeedRemark();
BE_SubmitMeshes();
RSpeedEnd(RSPEED_WORLD);
}
#endif

View File

@ -598,7 +598,6 @@ static qboolean D3D9_VID_Init(rendererstate_t *info, unsigned char *palette)
// pD3DX->lpVtbl->GetBufferSize((void*)pD3DX, &width, &height);
vid.pixelwidth = width;
vid.pixelheight = height;
vid.pixeloffset = -0.5;
vid.recalc_refdef = true;
vid.width = vid.conwidth = width;
@ -665,7 +664,7 @@ static void (D3D9_R_NewMap) (void)
int i;
r_worldentity.model = cl.worldmodel;
R_AnimateLight();
// D3D9_BuildLightmaps();
Surf_BuildLightmaps();
/*wipe any lingering particles*/
P_ClearParticles();
@ -768,7 +767,7 @@ static void D3D9_Set2D (void)
D3DVIEWPORT9 vport;
// IDirect3DDevice9_EndScene(pD3DDev9);
Matrix4_OrthographicD3D(m, 0, vid.width, 0, vid.height, -100, 100);
Matrix4_OrthographicD3D(m, 0 + (0.5*vid.width/vid.pixelwidth), vid.width + (0.5*vid.width/vid.pixelwidth), 0 + (0.5*vid.height/vid.pixelheight), vid.height + (0.5*vid.height/vid.pixelheight), -100, 100);
IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)m);
Matrix4_Identity(m);
@ -791,19 +790,13 @@ static void D3D9_Set2D (void)
vport.X = 0;
vport.Y = 0;
D3D9_GetBufferSize(&vport.Width, &vport.Height);
vport.Width = vid.pixelwidth;
vport.Height = vid.pixelheight;
vport.MinZ = 0;
vport.MaxZ = 1;
IDirect3DDevice9_SetViewport(pD3DDev9, &vport);
}
static void D3D9_GetBufferSize(int *width, int *height)
{
*width = vid.pixelwidth;
*height = vid.pixelheight;//vid.height;
// IDirect3DDevice9_GetBufferSize((void*)pD3DX, width, height);
}
static int d3d9error(int i)
{
if (FAILED(i))// != D3D_OK)
@ -925,8 +918,6 @@ static void (D3D9_SCR_UpdateScreen) (void)
VID_ShiftPalette (NULL);
}
vid.numpages = 2;// + gl_triplebuffer.value;
if (scr_disabled_for_loading)
{
extern float scr_disabled_time;
@ -1127,11 +1118,78 @@ static void (D3D9_R_Init) (void)
}
static void (D3D9_R_DeInit) (void)
{
Surf_DeInit();
}
static void D3D9_SetupViewPort(void)
{
extern cvar_t gl_mindist;
float screenaspect;
int x, x2, y2, y, w, h;
float fov_x, fov_y;
D3DVIEWPORT9 vport;
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
VectorCopy (r_refdef.vieworg, r_origin);
//
// set up viewpoint
//
x = r_refdef.vrect.x * vid.pixelwidth/(int)vid.width;
x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * vid.pixelwidth/(int)vid.width;
y = (r_refdef.vrect.y) * vid.pixelheight/(int)vid.height;
y2 = ((int)(r_refdef.vrect.y + r_refdef.vrect.height)) * vid.pixelheight/(int)vid.height;
// fudge around because of frac screen scale
if (x > 0)
x--;
if (x2 < vid.pixelwidth)
x2++;
if (y < 0)
y--;
if (y2 < vid.pixelheight)
y2++;
w = x2 - x;
h = y2 - y;
vport.X = x;
vport.Y = y;
vport.Width = w;
vport.Height = h;
vport.MinZ = 0;
vport.MaxZ = 1;
IDirect3DDevice9_SetViewport(pD3DDev9, &vport);
fov_x = r_refdef.fov_x;//+sin(cl.time)*5;
fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5;
if (r_waterwarp.value<0 && r_viewleaf->contents <= Q1CONTENTS_WATER)
{
fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value);
fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
}
screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height;
GL_InfinatePerspective(fov_x, fov_y, gl_mindist.value);
Matrix4_ModelViewMatrixFromAxis(r_view_matrix, vpn, vright, vup, r_refdef.vieworg);
IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)r_projection_matrix);
IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_view_matrix);
}
static void (D3D9_R_RenderView) (void)
{
d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0));
D3D9_SetupViewPort();
d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0));
Surf_DrawWorld();
P_DrawParticles ();
}
void (D3D9_R_NewMap) (void);

View File

@ -29444,6 +29444,10 @@
RelativePath="..\client\r_2d.c"
>
</File>
<File
RelativePath="..\client\r_surf.c"
>
</File>
</Filter>
<Filter
Name="d3d"

View File

@ -17,7 +17,7 @@
#ifdef GLQUAKE
#include "glquake.h"
#endif
#if defined(GLQUAKE)
#if defined(GLQUAKE) || defined(D3DQUAKE)
#ifdef _WIN32
#include <malloc.h>
@ -96,6 +96,7 @@ static hashtable_t skincolourmapped;
extern avec3_t shadevector, shadelight, ambientlight;
//changes vertex lighting values
#if 0
static void R_GAliasApplyLighting(mesh_t *mesh, vec3_t org, vec3_t angles, float *colormod)
{
int l, v;
@ -192,6 +193,7 @@ static void R_GAliasApplyLighting(mesh_t *mesh, vec3_t org, vec3_t angles, float
}
}
}
#endif
void GL_GAliasFlushSkinCache(void)
{
@ -343,7 +345,7 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, int surfnum,
{
inwidth = e->scoreboard->skin->width;
inheight = e->scoreboard->skin->height;
cm->texnum.base = GL_LoadTexture32(e->scoreboard->skin->name, inwidth, inheight, (unsigned int*)original, IF_NOALPHA|IF_NOGAMMA);
cm->texnum.base = R_LoadTexture32(e->scoreboard->skin->name, inwidth, inheight, (unsigned int*)original, IF_NOALPHA|IF_NOGAMMA);
return &cm->texnum;
}
}
@ -354,7 +356,7 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, int surfnum,
{
inwidth = e->scoreboard->skin->width;
inheight = e->scoreboard->skin->height;
cm->texnum.base = GL_LoadTexture(e->scoreboard->skin->name, inwidth, inheight, original, IF_NOALPHA|IF_NOGAMMA, 1);
cm->texnum.base = R_LoadTexture8(e->scoreboard->skin->name, inwidth, inheight, original, IF_NOALPHA|IF_NOGAMMA, 1);
return &cm->texnum;
}
}
@ -514,13 +516,8 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, int surfnum,
frac += fracstep;
}
}
texnums->base = GL_AllocNewTexture();
GL_Bind(texnums->base);
qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
texnums->base = R_AllocNewTexture(scaled_width, scaled_height);
R_Upload(texnums->base, "", TF_RGBX32, pixels, scaled_width, scaled_height, IF_NOMIPMAP);
//now do the fullbrights.
out = pixels;
@ -536,12 +533,8 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, int surfnum,
frac += fracstep;
}
}
texnums->fullbright = GL_AllocNewTexture();
GL_Bind(texnums->fullbright);
qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
texnums->fullbright = R_AllocNewTexture(scaled_width, scaled_height);
R_Upload(texnums->fullbright, "", TF_RGBA32, pixels, scaled_width, scaled_height, IF_NOMIPMAP);
}
else
{
@ -584,7 +577,7 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, int surfnum,
return texnums;
}
#if defined(RTLIGHTS) && defined(GLQUAKE)
static int numFacing;
static qbyte *triangleFacing;
static void R_CalcFacing(mesh_t *mesh, vec3_t lightpos)
@ -703,22 +696,7 @@ static void R_DrawShadowVolume(mesh_t *mesh)
}
qglEnd();
}
void GL_DrawAliasMesh (mesh_t *mesh, texid_t texnum)
{
shader_t shader;
memset(&shader, 0, sizeof(shader));
shader.numpasses = 1;
shader.passes[0].numMergedPasses = 1;
shader.passes[0].anim_frames[0] = texnum;
shader.passes[0].rgbgen = RGB_GEN_IDENTITY;
shader.passes[0].alphagen = ALPHA_GEN_IDENTITY;
shader.passes[0].shaderbits |= SBITS_MISC_DEPTHWRITE;
shader.passes[0].blendmode = GL_MODULATE;
shader.passes[0].texgen = T_GEN_SINGLEMAP;
BE_DrawMeshChain(&shader, mesh, NULL, NULL);
}
#endif
//true if no shading is to be used.
static qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel, unsigned int rmode)
@ -912,6 +890,7 @@ void R_DrawGAliasModel (entity_t *e, unsigned int rmode)
vec3_t saveorg;
int surfnum;
int bef;
float tmatrix[3][4];
@ -920,8 +899,6 @@ void R_DrawGAliasModel (entity_t *e, unsigned int rmode)
shader_t *shader;
currententity = e;
// if (e->flags & Q2RF_VIEWERMODEL && e->keynum == cl.playernum[r_refdef.currentplayernum]+1)
// return;
@ -969,15 +946,14 @@ void R_DrawGAliasModel (entity_t *e, unsigned int rmode)
if (e->flags & Q2RF_DEPTHHACK)
qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
BE_SelectMode(rmode, BEF_FORCEDEPTHTEST);
bef = BEF_FORCEDEPTHTEST;
if (e->flags & Q2RF_ADDITIVE)
{
BE_SelectMode(rmode, BEF_FORCEDEPTHTEST|BEF_FORCEADDITIVE);
bef |= BEF_FORCETRANSPARENT;
}
else if (e->drawflags & DRF_TRANSLUCENT)
{
BE_SelectMode(rmode, BEF_FORCEDEPTHTEST|BEF_FORCETRANSPARENT);
bef |= BEF_FORCETRANSPARENT;
e->shaderRGBAf[3] = r_wateralpha.value;
}
else if ((e->model->flags & EFH2_SPECIAL_TRANS)) //hexen2 flags.
@ -995,9 +971,9 @@ void R_DrawGAliasModel (entity_t *e, unsigned int rmode)
//(alpha test)
}
else if (e->shaderRGBAf[3] < 1)
{
BE_SelectMode(rmode, BEF_FORCEDEPTHTEST|BEF_FORCETRANSPARENT);
}
bef |= BEF_FORCETRANSPARENT;
BE_SelectMode(rmode, bef);
qglPushMatrix();
R_RotateForEntity(e);
@ -1129,8 +1105,6 @@ void R_DrawGAliasModel (entity_t *e, unsigned int rmode)
{
needrecolour = Alias_GAliasBuildMesh(&mesh, inf, e, e->shaderRGBAf[3], nolightdir);
c_alias_polys += mesh.numindexes/3;
shader = currententity->forcedshader;
skin = GL_ChooseSkin(inf, clmodel->name, surfnum, e);
@ -1182,6 +1156,7 @@ void R_DrawGAliasModel (entity_t *e, unsigned int rmode)
BE_SelectMode(rmode, 0);
}
#if defined(RTLIGHTS) && defined(GLQUAKE)
//returns result in the form of the result vector
void RotateLightVector(const vec3_t *axis, const vec3_t origin, const vec3_t lightpoint, vec3_t result)
{
@ -1416,7 +1391,7 @@ void R_DrawGAliasShadowVolume(entity_t *e, vec3_t lightpos, float radius)
qglPopMatrix();
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,8 @@ void GL_UploadFmt(texid_t tex, char *name, enum uploadfmt fmt, void *data, int w
case TF_INVALID:
break;
case TF_RGBX32:
flags |= IF_NOALPHA;
case TF_RGBA32:
GL_Upload32(name, data, width, height, flags);
break;
@ -85,6 +87,8 @@ texid_t GL_LoadTextureFmt (char *name, int width, int height, enum uploadfmt fmt
case TF_INVALID:
return r_nulltex;
case TF_RGBX32:
flags |= IF_NOALPHA;
case TF_RGBA32:
return GL_LoadTexture32(name, width, height, data, flags);
@ -313,7 +317,6 @@ Draw_Init
void GLDraw_ReInit (void)
{
char ver[40];
extern int *lightmap_textures;
int maxtexsize;

View File

@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
void GLDraw_Init (void);
void GLDraw_ReInit (void);
void GLDraw_DeInit (void);
void GLSurf_DeInit (void);
void Surf_DeInit (void);
void GLDraw_TransPicTranslate (int x, int y, int w, int h, qbyte *pic, qbyte *translation);
void GLDraw_BeginDisc (void);
void GLDraw_EndDisc (void);

View File

@ -3,6 +3,10 @@
#ifndef SERVERONLY
#include "shader.h"
#ifdef _WIN32
#include <windows.h>
#endif
void Font_Init(void);
void Font_Shutdown(void);
struct font_s *Font_LoadFont(int height, char *fontfilename);
@ -1033,8 +1037,8 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
if (c->texplane >= DEFAULTPLANE)
{
sx = ((px+vid.pixeloffset+c->left)*(int)vid.width) / (float)vid.pixelwidth;
sy = ((py+vid.pixeloffset+c->top)*(int)vid.height) / (float)vid.pixelheight;
sx = ((px+c->left)*(int)vid.width) / (float)vid.pixelwidth;
sy = ((py+c->top)*(int)vid.height) / (float)vid.pixelheight;
sw = ((curfont->charheight)*vid.width) / (float)vid.pixelwidth;
sh = ((curfont->charheight)*vid.height) / (float)vid.pixelheight;
@ -1045,8 +1049,8 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
}
else
{
sx = ((px-vid.pixeloffset+c->left)*(int)vid.width) / (float)vid.pixelwidth;
sy = ((py-vid.pixeloffset+c->top)*(int)vid.height) / (float)vid.pixelheight;
sx = ((px+c->left)*(int)vid.width) / (float)vid.pixelwidth;
sy = ((py+c->top)*(int)vid.height) / (float)vid.pixelheight;
sw = ((c->bmw+1)*vid.width) / (float)vid.pixelwidth;
sh = ((c->bmh+1)*vid.height) / (float)vid.pixelheight;
v = Font_BeginChar(fontplanes.texnum[c->texplane]);

View File

@ -2627,7 +2627,6 @@ float RadiusFromBounds (vec3_t mins, vec3_t maxs);
*/
//combination of R_AddDynamicLights and R_MarkLights
void GLR_StainSurf (msurface_t *surf, float *parms);
static void Q1BSP_StainNode (mnode_t *node, float *parms)
{
#ifdef GLQUAKE
@ -2659,7 +2658,7 @@ static void Q1BSP_StainNode (mnode_t *node, float *parms)
{
if (surf->flags&~(SURF_DONTWARP|SURF_PLANEBACK))
continue;
GLR_StainSurf(surf, parms);
Surf_StainSurf(surf, parms);
}
Q1BSP_StainNode (node->children[0], parms);

View File

@ -183,6 +183,9 @@ void GLR_RenderDlights (void)
// r_dlightframecount = r_framecount + 1; // because the count hasn't
// advanced yet for this frame
PPL_RevertToKnownState();
qglDepthMask (0);
qglDisable (GL_TEXTURE_2D);
qglShadeModel (GL_SMOOTH);

View File

@ -61,7 +61,6 @@ qboolean mirror;
mplane_t *mirror_plane;
msurface_t *r_mirror_chain;
qboolean r_inmirror; //or out-of-body
extern msurface_t *r_alpha_surfaces;
//
// view origin
@ -884,9 +883,6 @@ void R_PolyBlend (void)
PPL_RevertToKnownState();
GL_DisableMultitexture();
qglDisable (GL_ALPHA_TEST);
qglEnable (GL_BLEND);
qglDisable (GL_DEPTH_TEST);
@ -960,7 +956,7 @@ void GLR_BrightenScreen (void)
R_SetupFrame
===============
*/
void GLR_SetupFrame (void)
static void GLR_SetupFrame (void)
{
// don't allow cheats in multiplayer
r_wateralphaval = r_wateralpha.value;
@ -1080,6 +1076,10 @@ void R_SetupGL (void)
int x, x2, y2, y, w, h;
float fov_x, fov_y;
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
VectorCopy (r_refdef.vieworg, r_origin);
//
// set up viewpoint
//
@ -1192,8 +1192,6 @@ void R_RenderScene (void)
Sh_GenShadowMaps();
#endif
GLR_SetupFrame ();
TRACE(("dbg: calling R_SetupGL\n"));
R_SetupGL ();
@ -1207,7 +1205,7 @@ void R_RenderScene (void)
#endif
{
TRACE(("dbg: calling R_DrawWorld\n"));
R_DrawWorld (); // adds static entities to the list
Surf_DrawWorld (); // adds static entities to the list
}
}
@ -1218,9 +1216,6 @@ void R_RenderScene (void)
// R_DrawDecals();
TRACE(("dbg: calling GL_DisableMultitexture\n"));
GL_DisableMultitexture();
TRACE(("dbg: calling R_RenderDlights\n"));
GLR_RenderDlights ();
@ -1722,6 +1717,7 @@ static void R_RenderWaterWarp(void)
// copy the scene to texture
GL_Bind(scenepp_texture);
qglEnable(GL_TEXTURE_2D);
qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, vwidth, vheight, 0);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -1755,7 +1751,8 @@ static void R_RenderWaterWarp(void)
xmax = xmin + 1;
ymax = ymin + 1/vt*vs;
GL_EnableMultitexture();
GL_SelectTexture(1);
qglEnable(GL_TEXTURE_2D);
GL_Bind (scenepp_texture_warp);
GL_SelectTexture(2);
@ -1788,8 +1785,8 @@ static void R_RenderWaterWarp(void)
qglDisable(GL_TEXTURE_2D);
GL_SelectTexture(1);
GL_DisableMultitexture();
qglDisable(GL_TEXTURE_2D);
GL_SelectTexture(0);
}
// Disable shaders
@ -1934,8 +1931,6 @@ qboolean R_RenderScene_Fish(void)
// GLR_SetupFog ();
r_alpha_surfaces = NULL;
GL_SetShaderState2D(false);
// render normal view
@ -2084,8 +2079,6 @@ void GLR_RenderView (void)
// GLR_SetupFog ();
r_alpha_surfaces = NULL;
// render normal view
R_RenderScene ();

View File

@ -571,7 +571,7 @@ void GLR_DeInit (void)
GLDraw_DeInit();
GLSurf_DeInit();
Surf_DeInit();
}
void GLR_Init (void)
@ -1059,7 +1059,7 @@ void GLR_NewMap (void)
for (i=0 ; i<cl.worldmodel->numleafs ; i++)
cl.worldmodel->leafs[i].efrags = NULL;
GLSurf_DeInit();
Surf_DeInit();
r_viewleaf = NULL;
r_viewcluster = -1;
@ -1068,9 +1068,9 @@ void GLR_NewMap (void)
TRACE(("dbg: GLR_NewMap: clear particles\n"));
P_ClearParticles ();
TRACE(("dbg: GLR_NewMap: wiping them stains (getting the cloth out)\n"));
GLR_WipeStains();
Surf_WipeStains();
TRACE(("dbg: GLR_NewMap: building lightmaps\n"));
GL_BuildLightmaps ();
Surf_BuildLightmaps ();
TRACE(("dbg: GLR_NewMap: figuring out skys and mirrors\n"));
// identify sky texture
if (cl.worldmodel->fromgame != fg_quake2 && cl.worldmodel->fromgame != fg_quake3)

File diff suppressed because it is too large Load Diff

View File

@ -199,15 +199,16 @@ void GLSCR_UpdateScreen (void)
return; // not initialized yet
}
Shader_DoReload();
GL_BeginRendering ();
#ifdef VM_UI
uimenu = UI_MenuState();
#else
uimenu = 0;
#endif
GL_BeginRendering ();
Shader_DoReload();
#ifdef TEXTEDITOR
if (editormodal)
{

View File

@ -801,8 +801,8 @@ rendererinfo_t openglrendererinfo = {
GLR_PushDlights,
GLR_AddStain,
GLR_LessenStains,
Surf_AddStain,
Surf_LessenStains,
MediaGL_ShowFrameBGR_24_Flip,
MediaGL_ShowFrameRGBA_32,

View File

@ -772,7 +772,6 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
return false;
}
vid.pixeloffset = 0;
vid.colormap = host_colormap;
// interpret command-line params

View File

@ -501,7 +501,6 @@ qboolean VID_SetWindowedMode (rendererstate_t *info)
vid.conwidth = info->width;
vid.width = vid.conwidth;
vid.height = vid.conheight;
vid.pixeloffset = 0;
vid.numpages = 2;

View File

@ -563,6 +563,22 @@ static void GL_SkyForceDepth(msurface_t *fa)
}
}
static void FTE_DEPRECATED GL_DrawAliasMesh (mesh_t *mesh, texid_t texnum)
{
shader_t shader;
memset(&shader, 0, sizeof(shader));
shader.numpasses = 1;
shader.passes[0].numMergedPasses = 1;
shader.passes[0].anim_frames[0] = texnum;
shader.passes[0].rgbgen = RGB_GEN_IDENTITY;
shader.passes[0].alphagen = ALPHA_GEN_IDENTITY;
shader.passes[0].shaderbits |= SBITS_MISC_DEPTHWRITE;
shader.passes[0].blendmode = GL_MODULATE;
shader.passes[0].texgen = T_GEN_SINGLEMAP;
BE_DrawMeshChain(&shader, mesh, NULL, NULL);
}
static void GL_DrawSkySphere (msurface_t *fa)
{
extern cvar_t gl_maxdist;
@ -767,7 +783,7 @@ static void GL_DrawSkyGrid (texture_t *tex)
int i;
float time = cl.gametime+realtime-cl.gametimemark;
GL_DisableMultitexture();
PPL_RevertToKnownState();
GL_Bind (tex->shader->defaulttextures.base);
speedscale = time*8;

View File

@ -225,8 +225,6 @@ static void GLR_DrawSSector(unsigned int ssec)
sidedefsm[ld->sidedef[1-segsl[seg].direction]].texy,
vertexesl[v0].xpos, vertexesl[v0].ypos, sec->floorheight,
vertexesl[v1].xpos, vertexesl[v1].ypos, sec2->floorheight, ld->flags & LINEDEF_LOWERUNPEGGED);
c_brush_polys++;
}
if (sec->ceilingheight > sec2->ceilingheight)
@ -252,7 +250,6 @@ static void GLR_DrawSSector(unsigned int ssec)
glTexCoord2f(1, 1);
glVertex3f(vertexesl[v1].xpos, vertexesl[v1].ypos, sec2->ceilingheight);
glEnd();*/
c_brush_polys++;
}
if (sidedefsm[sd].middletex)
@ -295,7 +292,6 @@ static void GLR_DrawSSector(unsigned int ssec)
}
glEnd();
*/
c_brush_polys++;
}
}
else
@ -334,7 +330,6 @@ static void GLR_DrawSSector(unsigned int ssec)
}
glEnd();
#endif
c_brush_polys++;
}
}
}
@ -513,8 +508,6 @@ qboolean GLR_DoomWorld(void)
qglVertex3f(vertexesl[v1].xpos, vertexesl[v1].ypos, sectorm[i].ceilingheight);
}
qglEnd();
c_brush_polys += sectorm[i].numflattris;
}
}
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

View File

@ -190,19 +190,17 @@ FTE_DEPRECATED extern glvert_t glv;
void R_TimeRefresh_f (void);
FTE_DEPRECATED texture_t *SWR_TextureAnimation (texture_t *base);
texture_t *R_TextureAnimation (texture_t *base);
#include "particles.h"
//====================================================
extern entity_t r_worldentity;
extern vec3_t modelorg, r_entorigin;
extern vec3_t r_entorigin;
extern entity_t *currententity;
extern int r_visframecount; // ??? what difs?
extern int r_framecount;
extern mplane_t frustum[4];
FTE_DEPRECATED extern int c_brush_polys, c_alias_polys;
extern float r_wateralphaval;
@ -233,9 +231,6 @@ extern int mirrortexturenum; // quake texturenum, not gltexturenum
extern qboolean mirror;
extern mplane_t *mirror_plane;
extern float r_projection_matrix[16];
extern float r_view_matrix[16];
extern const char *gl_vendor;
extern const char *gl_renderer;
extern const char *gl_version;
@ -281,8 +276,6 @@ extern int mtexid1;
extern qboolean gl_mtexable;
void GL_DisableMultitexture(void);
void GL_EnableMultitexture(void);
void GL_SelectTexture (int tmunum);
void GL_SetShaderState2D(qboolean is2d);
@ -337,8 +330,8 @@ void GL_Set2D (void);
//
// gl_rmain.c
//
#ifdef GLQUAKE
qboolean R_CullBox (vec3_t mins, vec3_t maxs);
#ifdef GLQUAKE
qboolean R_CullSphere (vec3_t origin, float radius);
qboolean R_CullEntityBox(entity_t *e, vec3_t modmins, vec3_t modmaxs);
void R_RotateForEntity (entity_t *e);
@ -351,7 +344,6 @@ void GL_SetupSceneProcessingTextures (void);
// gl_alias.c
//
#ifdef GLQUAKE
void R_DrawGAliasModel (entity_t *e, unsigned int rmode);
void R_DrawGAliasShadowVolume(entity_t *e, vec3_t lightpos, float radius);
void R_LightArrays(vecV_t *coords, vec4_t *colours, int vertcount, vec3_t *normals);
@ -394,34 +386,10 @@ void R_InitBloomTextures(void);
//
#ifdef GLQUAKE
FTE_DEPRECATED void R_DrawBrushModel (entity_t *e);
void R_DrawWorld (void);
void GL_BuildLightmaps (void);
void R_RenderDynamicLightmaps (msurface_t *fa, int shift);
int GLR_LightmapShift (model_t *model);
void GL_LoadShaders(void);
#ifndef LMBLOCK_WIDTH
#define LMBLOCK_WIDTH 128
#define LMBLOCK_HEIGHT 128
typedef struct glRect_s {
unsigned char l,t,w,h;
} glRect_t;
typedef unsigned char stmap;
typedef struct {
mesh_t *meshchain;
qboolean modified;
qboolean deluxmodified;
glRect_t rectchange;
glRect_t deluxrectchange;
int allocated[LMBLOCK_WIDTH];
qbyte lightmaps[4*LMBLOCK_WIDTH*LMBLOCK_HEIGHT];
qbyte deluxmaps[4*LMBLOCK_WIDTH*LMBLOCK_HEIGHT]; //fixme: make seperate structure for easy disabling with less memory usage.
stmap stainmaps[3*LMBLOCK_WIDTH*LMBLOCK_HEIGHT]; //rgb no a. added to lightmap for added (hopefully) speed.
} lightmapinfo_t;
#endif
#endif
//gl_ppl.c
FTE_DEPRECATED void PPL_DrawWorld (qbyte *viewvis);

View File

@ -4123,8 +4123,8 @@ rendererinfo_t d3drendererinfo = {
GLR_PushDlights,
GLR_AddStain,
GLR_LessenStains,
Surf_AddStain,
Surf_LessenStains,
MediaGL_ShowFrameBGR_24_Flip,
MediaGL_ShowFrameRGBA_32,

View File

@ -393,20 +393,32 @@ void BE_SelectMode(backendmode_t mode, unsigned int flags);
//Draws an entire mesh chain from a VBO. vbo can be null, in which case the chain may be drawn without batching.
void BE_DrawMeshChain(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, texnums_t *texnums);
//submits the world and ents... used only by gl_shadows.c
void BE_SubmitMeshes (void);
//Asks the backend to invoke DrawMeshChain for each surface, and to upload lightmaps as required
void BE_DrawWorld (qbyte *vis);
//called at init, force the display to the right defaults etc
void BE_Init(void);
//Generates an optimised VBO, one for each texture on the map
void BE_GenBrushModelVBO(model_t *mod);
//Destroys the given vbo
void BE_ClearVBO(vbo_t *vbo);
//Uploads all modified lightmaps
void BE_UploadAllLightmaps(void);
#ifdef RTLIGHTS
//submits the world and ents... used only by gl_shadows.c
void BE_SubmitMeshes (void);
//sets up gl for depth-only FIXME
void BE_SetupForShadowMap(void);
//Generates shadow maps (called before anything is drawn in case it needs to clobber the normal view)
void Sh_GenShadowMaps (void);
//Draws lights, called from the backend
void Sh_DrawLights(qbyte *vis);
//Draws the depth of ents in the world near the current light
void BE_BaseEntShadowDepth(void);
//Sets the given light+colour to be the current one that everything is to be lit/culled by.
void BE_SelectDLight(dlight_t *dl, vec3_t colour);
//Returns true if the mesh is not lit by the current light
qboolean BE_LightCullModel(vec3_t org, model_t *model);
#endif

View File

@ -1363,7 +1363,7 @@ void NPP_QWWriteEntity(int dest, short data) //replacement write func (nq to qw)
#ifdef SERVER_DEMO_PLAYBACK
@ -2306,7 +2306,7 @@ void NPP_MVDWriteByte(qbyte data, client_t *to, int broadcast) //replacement wri
NPP_AddData(&data, sizeof(qbyte));
NPP_MVDCheckFlush();
}
#endif //SERVER_DEMO_PLAYBACK
void NPP_Flush(void)
{

View File

@ -391,6 +391,33 @@ int QCEditor (progfuncs_t *prinst, char *filename, int line, int nump, char **pa
#endif
}
model_t *SVPR_GetCModel(world_t *w, int modelindex)
{
if ((unsigned int)modelindex < MAX_MODELS)
return sv.models[modelindex];
else
return NULL;
}
void SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o)
{
int oself = pr_global_struct->self;
int oother = pr_global_struct->other;
pr_global_struct->self = EDICT_TO_PROG(w->progs, s);
pr_global_struct->other = EDICT_TO_PROG(w->progs, o);
pr_global_struct->time = w->physicstime;
#ifdef VM_Q1
if (w==&sv.world && svs.gametype == GT_Q1QVM)
Q1QVM_Touch();
else
#endif
PR_ExecuteProgram (w->progs, s->v->touch);
pr_global_struct->self = oself;
pr_global_struct->other = oother;
}
void Q_SetProgsParms(qboolean forcompiler)
{
progstype = PROG_NONE;
@ -434,6 +461,8 @@ void Q_SetProgsParms(qboolean forcompiler)
{
sv.world.progs = svprogfuncs = InitProgs(&svprogparms);
}
sv.world.Event_Touch = SVPR_Event_Touch;
sv.world.GetCModel = SVPR_GetCModel;
PR_ClearThreads();
PR_fclose_progs(svprogfuncs);
@ -1871,7 +1900,7 @@ void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m)
#endif
m = sv.strings.model_precache[i] = PR_AddString(prinst, m, 0);
if (!strcmp(m + strlen(m) - 4, ".bsp"))
sv.world.models[i] = Mod_FindName(m);
sv.models[i] = Mod_FindName(m);
Con_Printf("WARNING: SV_ModelIndex: model %s not precached\n", m);
if (sv.state != ss_loading)
@ -1932,7 +1961,7 @@ void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m)
//nq dedicated servers load bsps and mdls
//qw dedicated servers only load bsps (better)
mod = sv.world.models[i];
mod = sv.models[i];
if (mod)
{
mod = Mod_ForName (m, false);
@ -1962,7 +1991,7 @@ void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m)
}
else
{
if (sv.world.models[i])
if (sv.models[i])
{
mod = Mod_ForName (m, false);
if (mod)
@ -2005,7 +2034,7 @@ static void PF_frameforname (progfuncs_t *prinst, struct globalvars_s *pr_global
{
unsigned int modelindex = G_FLOAT(OFS_PARM0);
char *str = PF_VarString(prinst, 1, pr_globals);
model_t *mod = (modelindex>= MAX_MODELS)?NULL:sv.world.models[modelindex];
model_t *mod = (modelindex>= MAX_MODELS)?NULL:sv.models[modelindex];
if (mod && Mod_FrameForName)
G_FLOAT(OFS_RETURN) = Mod_FrameForName(mod, str);
@ -2022,9 +2051,9 @@ static void PF_frameduration (progfuncs_t *prinst, struct globalvars_s *pr_globa
G_FLOAT(OFS_RETURN) = 0;
else
{
mod = sv.world.models[modelindex];
mod = sv.models[modelindex];
if (!mod)
mod = sv.world.models[modelindex] = Mod_ForName(sv.strings.model_precache[modelindex], false);
mod = sv.models[modelindex] = Mod_ForName(sv.strings.model_precache[modelindex], false);
if (mod && Mod_GetFrameDuration)
G_FLOAT(OFS_RETURN) = Mod_GetFrameDuration(mod, framenum);
@ -2037,7 +2066,7 @@ static void PF_skinforname (progfuncs_t *prinst, struct globalvars_s *pr_globals
#ifndef SERVERONLY
unsigned int modelindex = G_FLOAT(OFS_PARM0);
char *str = PF_VarString(prinst, 1, pr_globals);
model_t *mod = (modelindex>= MAX_MODELS)?NULL:sv.world.models[modelindex];
model_t *mod = (modelindex>= MAX_MODELS)?NULL:sv.models[modelindex];
if (mod && Mod_SkinForName)
@ -2061,8 +2090,10 @@ void PF_bprint (progfuncs_t *prinst, struct globalvars_s *pr_globals)
char *s;
int level;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (progstype != PROG_QW)
{
@ -2095,8 +2126,10 @@ void PF_sprint (progfuncs_t *prinst, struct globalvars_s *pr_globals)
int entnum;
int level;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
entnum = G_EDICTNUM(prinst, OFS_PARM0);
@ -2157,8 +2190,10 @@ void PF_centerprint_Internal (int entnum, char *s)
client_t *cl, *sp;
int slen;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (entnum < 1 || entnum > sv.allocated_client_slots)
{
@ -3330,7 +3365,7 @@ int PF_precache_model_Internal (progfuncs_t *prinst, char *s)
sv.strings.model_precache[i] = PR_AddString(prinst, s, 0);
s = sv.strings.model_precache[i];
if (!strcmp(s + strlen(s) - 4, ".bsp"))
sv.world.models[i] = Mod_FindName(s);
sv.models[i] = Mod_FindName(s);
if (sv.state != ss_loading)
{
@ -4024,9 +4059,14 @@ void PF_WriteByte (progfuncs_t *prinst, struct globalvars_s *pr_globals)
return;
}
if (qc_nonetaccess.value || sv.demofile)
if (qc_nonetaccess.value)
return;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (progstype == PROG_NQ || progstype == PROG_H2)
{
NPP_NQWriteByte(G_FLOAT(OFS_PARM0), (qbyte)G_FLOAT(OFS_PARM1));
@ -4060,8 +4100,13 @@ void PF_WriteChar (progfuncs_t *prinst, struct globalvars_s *pr_globals)
return;
}
if (qc_nonetaccess.value || sv.demofile)
if (qc_nonetaccess.value)
return;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (progstype == PROG_NQ || progstype == PROG_H2)
{
NPP_NQWriteChar(G_FLOAT(OFS_PARM0), (char)G_FLOAT(OFS_PARM1));
@ -4095,8 +4140,12 @@ void PF_WriteShort (progfuncs_t *prinst, struct globalvars_s *pr_globals)
return;
}
if (qc_nonetaccess.value || sv.demofile)
if (qc_nonetaccess.value)
return;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (progstype == PROG_NQ || progstype == PROG_H2)
{
@ -4131,8 +4180,12 @@ void PF_WriteLong (progfuncs_t *prinst, struct globalvars_s *pr_globals)
return;
}
if (qc_nonetaccess.value || sv.demofile)
if (qc_nonetaccess.value)
return;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (progstype == PROG_NQ || progstype == PROG_H2)
{
@ -4167,8 +4220,13 @@ void PF_WriteAngle (progfuncs_t *prinst, struct globalvars_s *pr_globals)
return;
}
if (qc_nonetaccess.value || sv.demofile)
if (qc_nonetaccess.value)
return;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (progstype == PROG_NQ || progstype == PROG_H2)
{
NPP_NQWriteAngle(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
@ -4202,8 +4260,12 @@ void PF_WriteCoord (progfuncs_t *prinst, struct globalvars_s *pr_globals)
return;
}
if (qc_nonetaccess.value || sv.demofile)
if (qc_nonetaccess.value)
return;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (progstype == PROG_NQ || progstype == PROG_H2)
{
@ -4238,7 +4300,11 @@ void PF_WriteString_Internal (int target, char *str)
return;
}
if (qc_nonetaccess.value || sv.demofile)
if (qc_nonetaccess.value
#ifdef SERVER_DEMO_PLAYBACK
|| sv.demofile
#endif
)
return;
if (progstype == PROG_NQ || progstype == PROG_H2)
@ -4281,7 +4347,11 @@ void PF_WriteEntity (progfuncs_t *prinst, struct globalvars_s *pr_globals)
return;
}
if (qc_nonetaccess.value || sv.demofile)
if (qc_nonetaccess.value
#ifdef SERVER_DEMO_PLAYBACK
|| sv.demofile
#endif
)
return;
if (progstype == PROG_NQ || progstype == PROG_H2)
@ -4316,7 +4386,11 @@ void PF_WriteString2 (progfuncs_t *prinst, struct globalvars_s *pr_globals)
int old;
char *str;
if (G_FLOAT(OFS_PARM0) != MSG_CSQC && (qc_nonetaccess.value || sv.demofile))
if (G_FLOAT(OFS_PARM0) != MSG_CSQC && (qc_nonetaccess.value
#ifdef SERVER_DEMO_PLAYBACK
|| sv.demofile
#endif
))
return;
str = PF_VarString(prinst, 1, pr_globals);
@ -4403,9 +4477,10 @@ void SV_point_tempentity (vec3_t o, int type, int count) //count (usually 1) is
{
int split=0;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (type > TE_SUPERBULLET) //pick a new effect, cos this one we don't know about.
type = TE_SPIKE;
@ -6879,8 +6954,10 @@ void PF_plaque_draw(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *s;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
if (G_FLOAT(OFS_PARM1) == 0)
s = "";
@ -8207,7 +8284,7 @@ typedef struct zymbone_s
int SV_TagForName(int modelindex, char *tagname)
{
#if 1
model_t *model = sv.world.models[modelindex];
model_t *model = sv.models[modelindex];
if (!model)
model = Mod_ForName(sv.strings.model_precache[modelindex], false);
if (!model)
@ -8278,13 +8355,13 @@ void PF_setattachment(progfuncs_t *prinst, struct globalvars_s *pr_globals)
modelindex = (int)tagentity->v->modelindex;
if (modelindex > 0 && modelindex < MAX_MODELS)
{
if (!sv.world.models[modelindex])
sv.world.models[modelindex] = Mod_ForName(sv.strings.model_precache[modelindex], false);
if (sv.world.models[modelindex])
if (!sv.models[modelindex])
sv.models[modelindex] = Mod_ForName(sv.strings.model_precache[modelindex], false);
if (sv.models[modelindex])
{
tagidx = SV_TagForName(modelindex, tagname);
if (tagidx == 0)
Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, tagentity), tagname, tagname, NUM_FOR_EDICT(prinst, tagentity), sv.world.models[modelindex]->name);
Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, tagentity), tagname, tagname, NUM_FOR_EDICT(prinst, tagentity), sv.models[modelindex]->name);
}
else
Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): Couldn't load model %s\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, tagentity), tagname, sv.modelname[modelindex]);
@ -8317,7 +8394,7 @@ void PF_gettagindex(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
tagidx = SV_TagForName(modelindex, tagname);
if (tagidx == 0)
Con_DPrintf("PF_gettagindex(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, e), tagname, tagname, NUM_FOR_EDICT(prinst, e), sv.world.models[modelindex]->name);
Con_DPrintf("PF_gettagindex(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, e), tagname, tagname, NUM_FOR_EDICT(prinst, e), sv.models[modelindex]->name);
}
else
Con_DPrintf("PF_gettagindex(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, e), tagname, tagname, NUM_FOR_EDICT(prinst, e));
@ -8346,7 +8423,7 @@ void PF_sv_gettaginfo(progfuncs_t *prinst, struct globalvars_s *pr_globals)
float result[12];
edict_t *ent = G_EDICT(prinst, OFS_PARM0);
int tagnum = G_FLOAT(OFS_PARM1);
model_t *model = sv.world.models[(int)ent->v->modelindex];
model_t *model = sv.models[(int)ent->v->modelindex];
float *origin = G_VECTOR(OFS_RETURN);
float *axis[3];
@ -8638,7 +8715,7 @@ void PF_getsurfacenumpoints(progfuncs_t *prinst, struct globalvars_s *pr_globals
modelindex = ent->v->modelindex;
if (modelindex > 0 && modelindex < MAX_MODELS)
model = sv.world.models[(int)ent->v->modelindex];
model = sv.models[(int)ent->v->modelindex];
else
model = NULL;
@ -8661,7 +8738,7 @@ void PF_getsurfacepoint(progfuncs_t *prinst, struct globalvars_s *pr_globals)
modelindex = ent->v->modelindex;
if (modelindex > 0 && modelindex < MAX_MODELS)
model = sv.world.models[(int)ent->v->modelindex];
model = sv.models[(int)ent->v->modelindex];
else
model = NULL;
@ -8692,7 +8769,7 @@ void PF_getsurfacenormal(progfuncs_t *prinst, struct globalvars_s *pr_globals)
modelindex = ent->v->modelindex;
if (modelindex > 0 && modelindex < MAX_MODELS)
model = sv.world.models[(int)ent->v->modelindex];
model = sv.models[(int)ent->v->modelindex];
else
model = NULL;
@ -8725,7 +8802,7 @@ void PF_getsurfacetexture(progfuncs_t *prinst, struct globalvars_s *pr_globals)
modelindex = ent->v->modelindex;
if (modelindex > 0 && modelindex < MAX_MODELS)
model = sv.world.models[(int)ent->v->modelindex];
model = sv.models[(int)ent->v->modelindex];
else
model = NULL;
@ -8763,7 +8840,7 @@ void PF_getsurfacenearpoint(progfuncs_t *prinst, struct globalvars_s *pr_globals
modelindex = ent->v->modelindex;
if (modelindex > 0 && modelindex < MAX_MODELS)
model = sv.world.models[(int)ent->v->modelindex];
model = sv.models[(int)ent->v->modelindex];
else
model = NULL;

View File

@ -1316,6 +1316,9 @@ qboolean PR_LoadQ1QVM(void)
q1qvmprogfuncs.StringToProgs = Q1QVMPF_StringToProgs;
q1qvmprogfuncs.StringToNative = Q1QVMPF_StringToNative;
sv.world.Event_Touch = SVPR_Event_Touch;
sv.world.GetCModel = SVPR_GetCModel;
sv.world.num_edicts = 0; //we're not ready for most of the builtins yet
sv.world.max_edicts = 0; //so clear these out, just in case
sv.world.edict_size = 0; //if we get a division by zero, then at least its a safe crash

View File

@ -147,6 +147,7 @@ typedef struct
int allocated_client_slots; //number of slots available. (used mostly to stop single player saved games cacking up)
model_t *models[MAX_MODELS];
qbyte *pvs, *phs; // fully expanded and decompressed
// added to every client's unreliable buffer each frame, then cleared
@ -206,8 +207,8 @@ typedef struct
qboolean mvdrecording;
//====================================================
//this lot is for playback of demos
//this lot is for serverside playback of demos
#ifdef SERVER_DEMO_PLAYBACK
qboolean mvdplayback;
float realtime;
vfsfile_t *demofile; //also signifies playing the thing.
@ -260,6 +261,7 @@ typedef struct
char demfullmapname[64];
char *demolightstyles[MAX_LIGHTSTYLES];
#endif
//====================================================
entity_state_t extendedstatics[MAX_STATIC_ENTITIES];

View File

@ -1,6 +1,7 @@
#include "qwsvdef.h"
#ifndef CLIENTONLY
#ifdef SERVER_DEMO_PLAYBACK
void NPP_MVDWriteByte(qbyte data, client_t *to, int broadcast);
@ -603,10 +604,11 @@ qboolean SV_ReadMVD (void)
void SV_Demo_Init(void)
{
//Cmd_AddCommand("playmvd", SV_LoadClientDemo_f);
//Cmd_AddCommand("mvdplay", SV_LoadClientDemo_f);
// Cmd_AddCommand("svplay", SV_PlayDemo_f);
// Cmd_AddCommand("svrecord", SV_RecordDemo_f);
Cmd_AddCommand("playmvd", SV_LoadClientDemo_f);
Cmd_AddCommand("mvdplay", SV_LoadClientDemo_f);
Cmd_AddCommand("svplay", SV_PlayDemo_f);
Cmd_AddCommand("svrecord", SV_RecordDemo_f);
}
#endif
#endif //SERVER_DEMO_PLAYBACK
#endif //CLIENTONLY

View File

@ -160,6 +160,7 @@ void SV_EmitNailUpdate (sizebuf_t *msg, qboolean recorder)
MSG_WriteByte (msg, numnails);
#ifdef SERVER_DEMO_PLAYBACK
if (demonails)
{
for (n=0 ; n<numnails ; n++)
@ -192,6 +193,7 @@ void SV_EmitNailUpdate (sizebuf_t *msg, qboolean recorder)
return;
}
#endif
for (n=0 ; n<numnails ; n++)
{
ent = nails[n];
@ -1285,7 +1287,7 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent)
//we need to tell the client that it's moved, as it's own origin might not be natural
for (i=0 ; i<3 ; i++)
MSG_WriteCoord (msg, ent->origin[i]+(sv.demostatevalid?1:0));
MSG_WriteCoord (msg, ent->origin[i]);
MSG_WriteByte (msg, ent->frame);
@ -1433,11 +1435,13 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *
if (cl->state != cs_spawned)
continue;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostatevalid)
{
if (client != cl)
continue;
}
#endif
ent = cl->edict;
if (cl->viewent && ent == clent)
@ -1511,6 +1515,7 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *
return;
#endif
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostatevalid) //this is a demo
{
usercmd_t cmd;
@ -1641,7 +1646,7 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *
}
return;
}
#endif
for (j=0,cl=svs.clients ; j<sv.allocated_client_slots ; j++,cl++)
{
if (cl->state != cs_spawned || (cl->state == cs_free && cl->name[0])) //this includes bots, and nq bots
@ -1749,8 +1754,10 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *
if (ent != vent || host_client->viewent == j+1)
clst.modelindex = 0;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostatevalid)
clst.health = 100;
#endif
clst.isself = false;
if ((cl == client || cl->controller == client))
@ -2138,7 +2145,8 @@ qboolean Q2BSP_EdictInFatPVS(model_t *mod, wedict_t *ent, qbyte *pvs)
}
#endif
void SV_Snapshot_Build_Playback(client_t *client, packet_entities_t *pack)
#ifdef SERVER_DEMO_PLAYBACK
static void SV_Snapshot_Build_Playback(client_t *client, packet_entities_t *pack)
{
int e;
entity_state_t *state;
@ -2195,6 +2203,7 @@ void SV_Snapshot_Build_Playback(client_t *client, packet_entities_t *pack)
continue;
}
}
#endif
void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *client)
{
@ -2731,11 +2740,13 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
// put other visible entities into either a packet_entities or a nails message
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostatevalid) //generate info from demo stats
{
SV_Snapshot_Build_Playback(client, pack);
}
else
#endif
{
#ifdef HLSERVER
if (svs.gametype == GT_HALFLIFE)

View File

@ -62,7 +62,7 @@ int SV_ModelIndex (char *name)
{
Q_strncpyz(sv.strings.model_precache[i], name, sizeof(sv.strings.model_precache[i]));
if (!strcmp(name + strlen(name) - 4, ".bsp"))
sv.world.models[i] = Mod_FindName(sv.strings.model_precache[i]);
sv.models[i] = Mod_FindName(sv.strings.model_precache[i]);
Con_Printf("WARNING: SV_ModelIndex: model %s not precached\n", name);
}
else
@ -108,6 +108,7 @@ void SV_FlushSignon (void)
sv.num_signon_buffers++;
sv.signon.cursize = 0;
}
#ifdef SERVER_DEMO_PLAYBACK
void SV_FlushDemoSignon (void)
{
if (sv.demosignon.cursize < sv.demosignon.maxsize - 512)
@ -121,7 +122,7 @@ void SV_FlushDemoSignon (void)
sv.num_demosignon_buffers++;
sv.demosignon.cursize = 0;
}
#endif
/*
================
SV_CreateBaseline
@ -935,7 +936,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
#endif
sv.world.models[1] = sv.world.worldmodel;
sv.models[1] = sv.world.worldmodel;
#ifdef VM_Q1
if (svs.gametype == GT_Q1QVM)
{
@ -946,7 +947,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
for (i=1 ; i<sv.world.worldmodel->numsubmodels ; i++)
{
sv.strings.model_precache[1+i] = localmodels[i];
sv.world.models[i+1] = Mod_ForName (localmodels[i], false);
sv.models[i+1] = Mod_ForName (localmodels[i], false);
}
//check player/eyes models for hacks
@ -964,7 +965,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
for (i=1 ; i<sv.world.worldmodel->numsubmodels ; i++)
{
sv.strings.model_precache[1+i] = PR_AddString(svprogfuncs, localmodels[i], 0);
sv.world.models[i+1] = Mod_ForName (localmodels[i], false);
sv.models[i+1] = Mod_ForName (localmodels[i], false);
}
//check player/eyes models for hacks
@ -994,7 +995,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
for (i=1; i<sv.world.worldmodel->numsubmodels; i++)
{
strcpy(sv.strings.configstring[Q2CS_MODELS+1+i], localmodels[i]);
sv.world.models[i+1] = Mod_ForName (localmodels[i], false);
sv.models[i+1] = Mod_ForName (localmodels[i], false);
}
}
#endif

View File

@ -793,6 +793,7 @@ void SV_FullClientUpdate (client_t *client, sizebuf_t *buf, unsigned int ftepext
i = client - svs.clients;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
{
MSG_WriteByte (buf, svc_updatefrags);
@ -822,6 +823,7 @@ void SV_FullClientUpdate (client_t *client, sizebuf_t *buf, unsigned int ftepext
MSG_WriteString (buf, info);
return;
}
#endif
//Sys_Printf("SV_FullClientUpdate: Updated frags for client %d\n", i);
@ -911,12 +913,14 @@ void SV_FullClientUpdateToClient (client_t *client, client_t *cl)
else
#endif
{
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
{
int i = client - svs.clients;
ClientReliableCheckBlock(cl, 24 + strlen(sv.recordedplayer[i].userinfo));
}
else
#endif
ClientReliableCheckBlock(cl, 24 + strlen(client->userinfo));
if (cl->num_backbuf) {
SV_FullClientUpdate (client, &cl->backbuf, cl->fteprotocolextensions);
@ -2862,8 +2866,11 @@ void SV_OpenRoute_f(void)
SV_ReadPackets
=================
*/
#ifdef SERVER_DEMO_PLAYBACK
//FIMXE: move to header
qboolean SV_GetPacket (void);
#endif
qboolean SV_ReadPackets (void)
{
int i;
@ -2911,7 +2918,11 @@ qboolean SV_ReadPackets (void)
}
}
while (SV_GetPacket ())
#ifdef SERVER_DEMO_PLAYBACK
while (SV_GetPacket())
#else
while (NET_GetPacket (NS_SERVER))
#endif
{
banreason = SV_BannedReason (&net_from);
if (banreason)
@ -3401,7 +3412,9 @@ void SV_MVDStream_Poll(void);
PR_SQLCycle();
#endif
#ifdef SERVER_DEMO_PLAYBACK
while(SV_ReadMVD());
#endif
if (sv.multicast.cursize)
{
@ -4312,8 +4325,11 @@ void SV_IgnoreCommand_f(void)
SV_Init
====================
*/
#ifdef SERVER_DEMO_PLAYBACK
//FIXME: move to header
void SV_Demo_Init(void);
#endif
void SV_Init (quakeparms_t *parms)
{
int i;
@ -4356,7 +4372,9 @@ void SV_Init (quakeparms_t *parms)
IWebInit();
#endif
#ifdef SERVER_DEMO_PLAYBACK
SV_Demo_Init();
#endif
#ifdef USEODE
World_Physics_Init();

View File

@ -1497,6 +1497,7 @@ void SV_UpdateClientStats (client_t *client, int pnum)
PR_ExecuteProgram(svprogfuncs, getplayerstat[i]);
statsf[i] = G_FLOAT(OFS_RETURN);
}
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
{
if (!client->spec_track)
@ -1511,6 +1512,7 @@ void SV_UpdateClientStats (client_t *client, int pnum)
statsi[i] = sv.recordedplayer[client->spec_track - 1].stats[i];
}
}
#endif
if (!ISQWCLIENT(client))
{
if (!statsi[i])

View File

@ -283,11 +283,14 @@ void SV_New_f (void)
default:
playernum = NUM_FOR_EDICT(svprogfuncs, split->edict)-1;
}
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostate)
{
playernum = (MAX_CLIENTS-1-splitnum)|128;
}
else if (split->spectator)
else
#endif
if (split->spectator)
playernum |= 128;
if (sv.state == ss_cinematic)
@ -310,9 +313,11 @@ void SV_New_f (void)
ClientReliableWrite_Byte (host_client, 128);
// send full levelname
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostatevalid)
ClientReliableWrite_String (host_client, sv.demfullmapname);
else
#endif
ClientReliableWrite_String (host_client, sv.mapname);
//
@ -345,6 +350,7 @@ void SV_New_f (void)
ClientReliableWrite_Float(host_client, movevars.waterfriction);
ClientReliableWrite_Float(host_client, movevars.entgravity);
#ifdef SERVER_DEMO_PLAYBACK
// send server info string
if (sv.demostatevalid)
{
@ -353,6 +359,7 @@ void SV_New_f (void)
ClientReliableWrite_String (host_client, va("fullserverinfo \"%s\"\n", sv.demoinfo) );
}
else
#endif
{
ClientReliableCheckBlock(host_client, 20 + strlen(svs.info));
ClientReliableWrite_Byte (host_client, svc_stufftext);
@ -869,6 +876,7 @@ void SV_Soundlist_f (void)
maxclientsupportedsounds *= 2;
#endif
#ifdef SERVER_DEMO_PLAYBACK
if (sv.democausesreconnect) //read the list from somewhere else
{
for (i = 1+n;
@ -881,6 +889,7 @@ void SV_Soundlist_f (void)
n = 0;
}
else
#endif
{
for (i = 1+n;
i < maxclientsupportedsounds && *sv.strings.sound_precache[i] && host_client->netchan.message.cursize < (MAX_QWMSGLEN/2);
@ -999,6 +1008,7 @@ void SV_Modellist_f (void)
maxclientsupportedmodels *= 2;
#endif
#ifdef SERVER_DEMO_PLAYBACK
if (sv.democausesreconnect) //read the list from somewhere else
{
for (i = 1+n;
@ -1010,6 +1020,7 @@ void SV_Modellist_f (void)
n = 0;
}
else
#endif
{
for (i = 1+n;
i < maxclientsupportedmodels && sv.strings.model_precache[i] && host_client->netchan.message.cursize < (MAX_QWMSGLEN/2); //make sure we don't send a 0 next...
@ -1060,9 +1071,11 @@ void SV_PreSpawn_f (void)
return;
}
#ifdef SERVER_DEMO_PLAYBACK
if (sv.democausesreconnect)
bufs = sv.num_demosignon_buffers;
else
#endif
bufs = sv.num_signon_buffers;
statics = sv.numextrastatics;
buf = atoi(Cmd_Argv(2));
@ -1084,7 +1097,9 @@ void SV_PreSpawn_f (void)
if (sv_mapcheck.value && check != sv.world.worldmodel->checksum &&
check != COM_RemapMapChecksum(LittleLong(sv.world.worldmodel->checksum2)))
#ifdef SERVER_DEMO_PLAYBACK
if (!sv.demofile || (sv.demofile && !sv.democausesreconnect)) //demo playing causes no check. If it's the return level, check anyway to avoid that loophole.
#endif
{
SV_ClientTPrintf (host_client, PRINT_HIGH,
STL_MAPCHEAT,
@ -1106,7 +1121,11 @@ void SV_PreSpawn_f (void)
return;
}
if (buf >= bufs && !sv.democausesreconnect)
if (buf >= bufs
#ifdef SERVER_DEMO_PLAYBACK
&& !sv.democausesreconnect
#endif
)
{
int i;
entity_state_t from;
@ -1246,6 +1265,7 @@ void SV_PreSpawn_f (void)
}
else
{
#ifdef SERVER_DEMO_PLAYBACK
if (sv.democausesreconnect)
{
if (host_client->netchan.message.cursize+sv.signon_buffer_size[buf]+30 < host_client->netchan.message.maxsize)
@ -1257,6 +1277,7 @@ void SV_PreSpawn_f (void)
}
}
else
#endif
{
if (host_client->netchan.message.cursize+sv.signon_buffer_size[buf]+30 < host_client->netchan.message.maxsize)
{
@ -1320,6 +1341,7 @@ void SV_Spawn_f (void)
// send all current light styles
for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
{
#ifdef SERVER_DEMO_PLAYBACK
if (sv.democausesreconnect)
{
if (i >= MAX_STANDARDLIGHTSTYLES)
@ -1330,6 +1352,7 @@ void SV_Spawn_f (void)
ClientReliableWrite_String (host_client, sv.demolightstyles[i]);
}
else
#endif
{
if (i >= MAX_STANDARDLIGHTSTYLES)
if (!sv.strings.lightstyles[i])
@ -2753,6 +2776,7 @@ void SV_Pings_f (void)
client_t *client;
int j;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
{
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
@ -2768,7 +2792,7 @@ void SV_Pings_f (void)
}
return;
}
#endif
if (ISNQCLIENT(host_client))
{
char *s;
@ -2946,7 +2970,11 @@ void SV_PTrack_f (void)
int i;
edict_t *ent, *tent;
if (!host_client->spectator && !sv.demofile)
if (!host_client->spectator
#ifdef SERVER_DEMO_PLAYBACK
&& !sv.demofile
#endif
)
return;
if (Cmd_Argc() != 2)
@ -2960,11 +2988,13 @@ void SV_PTrack_f (void)
}
i = atoi(Cmd_Argv(1));
#ifdef SERVER_DEMO_PLAYBACK
if (*sv.recordedplayer[i].userinfo)
{
host_client->spec_track = i+1;
return;
}
#endif
if (i < 0 || i >= MAX_CLIENTS || svs.clients[i].state != cs_spawned ||
svs.clients[i].spectator)
@ -4683,7 +4713,7 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
{
if(progstype != PROG_H2)
pe->angles[0]*=-1; //quake is wierd. I guess someone fixed it hexen2... or my code is buggy or something...
pe->model = sv.world.models[(int)(check->v->modelindex)];
pe->model = sv.models[(int)(check->v->modelindex)];
VectorCopy (check->v->angles, pe->angles);
}
else
@ -4715,7 +4745,7 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
if (!((int)player->xv->dimension_hit & (int)check->xv->dimension_solid))
continue;
model = sv.world.models[(int)check->v->modelindex];
model = sv.models[(int)check->v->modelindex];
if (model)
// test the point
if (model->funcs.PointContents (model, player->v->origin) == FTECONTENTS_SOLID)
@ -4777,7 +4807,7 @@ void AddAllEntsToPmove (void)
if (check->v->solid == SOLID_BSP)
{
VectorCopy (check->v->angles, pe->angles);
pe->model = sv.world.models[(int)(check->v->modelindex)];
pe->model = sv.models[(int)(check->v->modelindex)];
}
else
{
@ -4795,12 +4825,14 @@ void AddAllEntsToPmove (void)
int SV_PMTypeForClient (client_t *cl)
{
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostatevalid)
{ //force noclip... This does create problems for closing demos.
if (cl->zquake_extensions & Z_EXT_PM_TYPE_NEW)
return PM_SPECTATOR;
return PM_OLD_SPECTATOR;
}
#endif
if (sv_brokenmovetypes.value) //this is to mimic standard qw servers, which don't support movetypes other than MOVETYPE_FLY.
{ //it prevents bugs from being visible in unsuspecting mods.
@ -4926,6 +4958,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
if (host_frametime > 0.1)
host_frametime = 0.1;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostatevalid)
{ //spectators watching MVDs do not affect the running progs.
player_mins[0] = -16;
@ -4977,6 +5010,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
return;
}
#endif
#ifdef SVCHAT
if (SV_ChatMove(ucmd->impulse))
@ -5756,11 +5790,14 @@ haveannothergo:
o[1] = MSG_ReadCoord();
o[2] = MSG_ReadCoord();
// only allowed by spectators
#ifdef SERVER_DEMO_PLAYBACK
if (sv.mvdplayback)
{
VectorCopy(o, host_client->specorigin);
}
else if (host_client->spectator)
else
#endif
if (host_client->spectator)
{
VectorCopy(o, sv_player->v->origin);
World_LinkEdict(&sv.world, (wedict_t*)sv_player, false);

View File

@ -22,8 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h"
#include "pr_common.h"
//#define pr_global_struct dgsdfg sdfg sdfg sd gsgd
#ifndef CLIENTONLY
/*
@ -187,7 +185,15 @@ void World_ClearWorld (world_t *w)
memset (w->areanodes, 0, sizeof(w->areanodes));
w->numareanodes = 0;
World_CreateAreaNode (w, 0, w->worldmodel->mins, w->worldmodel->maxs);
if (!w->worldmodel)
{
vec3_t mins, maxs;
VectorSet(mins, -4096, -4096, -4096);
VectorSet(maxs, 4096, 4096, 4096);
World_CreateAreaNode (w, 0, mins, maxs);
}
else
World_CreateAreaNode (w, 0, w->worldmodel->mins, w->worldmodel->maxs);
}
@ -217,7 +223,6 @@ void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node)
{
link_t *l, *next;
wedict_t *touch;
int old_self, old_other;
int linkcount = 0, ln;
@ -248,8 +253,6 @@ void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node)
nodelinks[linkcount++] = touch;
}
old_self = pr_global_struct->self;
old_other = pr_global_struct->other;
for (ln = 0; ln < linkcount; ln++)
{
touch = nodelinks[ln];
@ -271,21 +274,11 @@ void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node)
if (!((int)ent->xv->dimension_solid & (int)touch->xv->dimension_hit)) //didn't change did it?...
continue;
pr_global_struct->self = EDICT_TO_PROG(w->progs, touch);
pr_global_struct->other = EDICT_TO_PROG(w->progs, ent);
pr_global_struct->time = w->physicstime;
#ifdef VM_Q1
if (w==&sv.world && svs.gametype == GT_Q1QVM)
Q1QVM_Touch();
else
#endif
PR_ExecuteProgram (w->progs, touch->v->touch);
w->Event_Touch(w, touch, ent);
if (ent->isfree)
break;
}
pr_global_struct->self = old_self;
pr_global_struct->other = old_other;
// recurse down both sides
@ -474,7 +467,8 @@ void World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers)
}
// link to PVS leafs
w->worldmodel->funcs.FindTouchedLeafs_Q1(w, w->worldmodel, ent, ent->v->absmin, ent->v->absmax);
if (w->worldmodel)
w->worldmodel->funcs.FindTouchedLeafs_Q1(w, w->worldmodel, ent, ent->v->absmin, ent->v->absmax);
/*
#ifdef Q2BSPS
if (w->worldmodel->fromgame == fg_quake2 || w->worldmodel->fromgame == fg_quake3)
@ -1106,7 +1100,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
// get the clipping hull
if (ent->v->solid == SOLID_BSP)
{
model = w->models[(int)ent->v->modelindex];
model = w->GetCModel(w, ent->v->modelindex);
if (!model || (model->type != mod_brush && model->type != mod_heightmap))
SV_Error("SOLID_BSP with non bsp model (classname: %s)", PR_GetString(svprogfuncs, ent->v->classname));
}
@ -1141,12 +1135,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
model_t *model;
if (ent->v->modelindex < 1 || ent->v->modelindex >= MAX_MODELS)
SV_Error("SV_ClipMoveToEntity: modelindex out of range\n");
model = w->models[ (int)ent->v->modelindex ];
if (!model)
{ //if the model isn't loaded, load it.
//this saves on memory requirements with mods that don't ever use this.
model = w->models[(int)ent->v->modelindex] = Mod_ForName(sv.strings.model_precache[(int)ent->v->modelindex], false);
}
model = w->GetCModel(w, ent->v->modelindex);
if (model && model->funcs.Trace)
{
@ -1177,7 +1166,7 @@ static trace_t WorldQ2_ClipMoveToEntity (world_t *w, q2edict_t *ent, vec3_t star
// get the clipping hull
if (ent->s.solid == Q2SOLID_BSP)
{
model = w->models[(int)ent->s.modelindex];
model = w->GetCModel(w, ent->s.modelindex);
if (!model || model->type != mod_brush)
SV_Error("SOLID_BSP with non bsp model");
}
@ -1373,7 +1362,7 @@ static model_t *WorldQ2_ModelForEntity (world_t *w, q2edict_t *ent)
// decide which clipping hull to use, based on the size
if (ent->solid == Q2SOLID_BSP)
{ // explicit hulls in the BSP model
model = w->models[ (int)ent->s.modelindex ];
model = w->GetCModel(w, ent->s.modelindex);
if (!model)
SV_Error ("Q2SOLID_BSP with a non bsp model");

326
specs/qc_extensions.txt Normal file
View File

@ -0,0 +1,326 @@
//default to ssqc, as that's the most common sort of mod in use.
#ifndef CSQC
#ifndef MENU
#ifndef SSQC
#define SSQC
#endif
#endif
#endif
//EXT_BITSHIFT
//if quantity is negative, value is shifted right.
//if quantity is positive, value is shifted left.
//be warned that floats are not ideal for precision...
float(float number, float quantity) bitshift = #218;
//EXT_DIMENSION_VISIBILITY
//if (player.dimension_see && other.dimension_seen) then allow entity to be visible to client. This affects which entities are visible to each other.
//dimension_send is equivelent to seen, but applies to multicasts instead of entities.
//suggestion: this extension can be used to filter ents based on csqc support or not.
#ifdef SSQC
.float dimension_see;
.float dimension_seen;
float dimension_send;
#endif
//EXT_DIMENSION_GHOST
//if self.dimension_ghost specifies a bit which is not in dimension_seen, then the entity can still be seen but its alpha value will be multiplied by ghost_alpha (or 0.5 if that's set to 0).
#ifdef SSQC
.float dimension_ghost;
.float dimension_ghost_alpha;
#endif
//EXT_DIMENSION_PHYSICS
//provides two (float) bitfields that control whether two entities are allowed to collide, and in which direction.
//logically: if (self.dimention_hit & other.dimension_solid) self.touch();
//note that if one ent is solid one way, and not the other, one may move through while the other cannot (unless its already inside).
.float dimension_solid;
.float dimension_hit;
//FTE_CALLTIMEOFDAY
//originally an mvdsv extension, but in a builtin number that wasn't compatible (was 102).
//calltimeofday invokes a timeofday function with arguments containing the time of day, oddly enough.
void() calltimeofday = #231;
//In order to make it more useful, this header includes a timeofday function which just grabs the values for you to use in your qc code straight after calling calltimeofday.
float tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year;
string tod_string;
//This function is to facilitate use, and need not be modified.
void(float s, float mi, float h, float d, float mo, float y, string tmp_timeofday) timeofday =
{ tod_sec = s; tod_min = mi; tod_hour = h; tod_day = d; tod_mon = mo; tod_year = y; strunzone(tod_string); tod_string = strzone(tmp_timeofday);};
//FTE_CSQC_HALFLIFE_MODELS
//engine supports halflife models.
#ifdef CSQC
.float bonecontrol1;
.float bonecontrol2;
.float bonecontrol3;
.float bonecontrol4;
.float bonecontrol5; /*aka mouth*/
.float subblendfrac;
.float basesubblendfrac; /*depends upon FTE_CSQC_BASEFRAME*/
#endif
//FTE_CSQC_BASEFRAME
#ifdef CSQC
.float baseframe;
.float baseframe2;
.float baselerpfrac;
.float baseframe1time;
.float baseframe2time;
.float basebone;
#endif
//FTE_CSQC_SKELETONOBJECTS
//idea: Spike, LordHavoc
//builtin definitions:
#ifdef CSQC
float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign the value to .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal)
float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .lerpfrac, .frame1time, .frame2time, FTE_CSQC_BASEFRAME fields), returns skel on success, 0 on failure
float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton
string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring)
float(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, -1 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
float(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex
vector(float skel, float bonenum) skel_get_bonerel = #269; // get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
vector(float skel, float bonenum) skel_get_boneabs = #270; // get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
void(float skel, float bonenum, vector org) skel_set_bone = #271; // set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
void(float skel, float bonenum, vector org) skel_mul_bone = #272; // transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
void(float skel) skel_delete = #275; // deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
float(float modlindex, string framename) frameforname = #276; // finds number of a specified frame in the animation, returns -1 if no match found
float(float modlindex, float framenum) frameduration = #277; // returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
//fields:
.float skeletonindex; // active skeleton overriding standard animation on model
.float frame; // primary framegroup animation (strength = 1 - lerpfrac)
.float frame2; // secondary framegroup animation (strength = lerpfrac)
.float lerpfrac; // strength of framegroup blend
.float frame1time; // start time of framegroup animation
.float frame2time; // start time of framegroup animation
#endif
//description:
//this extension provides a way to do complex skeletal animation on an entity.
//
//see also DP_SKELETONOBJECTS (this extension implemented on server as well as client)
//
//notes:
//each model contains its own skeleton, reusing a skeleton with incompatible models will yield garbage (or not render).
//each model contains its own animation data, you can use animations from other model files (for example saving out all character animations as separate model files).
//if an engine supports loading an animation-only file format such as .md5anim in FTEQW, it can be used to animate any model with a compatible skeleton.
//proper use of this extension may require understanding matrix transforms (v_forward, v_right, v_up, origin), and you must keep in mind that v_right is negative for this purpose.
//
//features include:
//multiple animations blended together.
//animating a model with animations from another model with a compatible skeleton.
//restricting animation blends to certain bones of a model - for example independent animation of legs, torso, head.
//custom bone controllers - for example making eyes track a target location.
//FTE_ENT_UNIQUESPAWNID
//Provides a field that is incremented each time an entity is spawn()ed. Always changes so no two spawn()s have the same value.
.float uniquespawnid;
//FTE_EXTENDEDTEXTCODES
//FTE_FORCEINFOKEY
forceinfokey
//FTE_GFX_QUAKE3SHADERS
//The engine supports Q3-compatible shaders, to the best of its ability. Specifically on models.
#ifdef CSQC
//returns a skin value that can be used on entities with the given modelindex for the given .skin file name.
float(float modelindex, string skinname) skinforname = #237;
//returns a shader id which can be passed back into the engine.
float(string shadername) shaderforname = #238;
//if set on an entity, forces all surfaces of the entity to use that shader.
.float forceshader;
#endif
//FTE_ISBACKBUFFERED
//idea: Spike
//Adds a builtin that allows you to see if data sent to a player will likely just be buffered.
//This permits ensuring that it does not overflow and get kicked, nor block other data for long periods, if you wish to generate/send a lot of data at once.
float(entity playerent) isbackbuffered = #233;
//FTE_MEDIA_AVI
//specifies that the playfilm command and associated functionality accepts .avi format files.
//FTE_MEDIA_CIN
//specifies that the playfilm command and associated functionality accepts .cin format (q2) files.
//FTE_MEDIA_ROQ
//specifies that the playfilm command and associated functionality accepts RoQ format (q3) files.
//FTE_MULTIPROGS
//multiprogs: aka mutators or addons.
//Even if you do not use addons, you are able to use this extension to query globals and stuff by name within the current progs.
//The actual form of these builtins:
//__variant(float progsnum, string funcname, ...) externcall = #201; /*calls a function by name in another progs. Accepts up to 6 additional arguments to pass through.*/
//__variant(float progsnum, string varname) externvalue = #203; /*retrieves a value from another progs by name*/
//Convienience:
float(float progsnum, string funcname, ...) externcall_f = #201;
float(float progsnum, string varname) externvalue_f = #203;
vector(float progsnum, string funcname, ...) externcall_v = #201; /*calls a function, expects a vector response*/
vector(float progsnum, string varname) externvalue_v = #203;
//other funcs
void(float progsnum, string varname, ...) externset = #204; /*sets a global/function/field-index in a given progs. Argument is passed in the ... bit (variant, will expect a vector only if the changed var type is a vector)*/
float(string fname) addprogs = #202; /*not always valid after initents has been called*/
float thisprogs;
//engine-callable functions
//void() init; /*called as soon as the progs is loaded - warning don't call spawn(). Hook your parent's functions here.*/
//void() initents; /*called once addons are already loaded. Init the rest of your code here.*/
//void(string pname) AddAddonProgs; /*engine asks main progs to add an addon*/
//FTE_MULTITHREADED
//FTE provides a pseudo-threading mechanism (cooperative execution threads).
//Such threads preserve their entire QC stack, but not the engine stack beforehand.
//The only globals that are thread-local are self and other. All others might be changed by any other task between scheduling.
//As threads are cooperative, so there is no dire need for mutexes so long as you make no assumptions over sleeps/forks.
//Note that fork forks the thread, so you can return twice from the same function. Use abort to prevent such unexpected situations.
//The engine requires that the thread return to it. Thus sleep conceptually acts as an if(!fork())abort(0); pair in situations where the engine depends upon return values.
//Expected usage is to fork on an event, invoke sleep with periodic intervals triggering sub-events, and eventually calling abort on the forked thread.
//A forked or sleeped thread should not return twice through engine code.
//Be aware that entities can be freed while your thread is sleeping. Use the wasfreed builtin or uniquespawnid field to detect this situation.
void(float secs) sleep = #212; /*Causes the current QC execution thread to stop and sleep for X secs. If the engine expected a return value from the current thread, then 0 is forcibly returned - consider: if (!fork())abort(5); if you need a different return value.*/
float() fork = #210; /*called once, returns twice, with two different return values. If the engine expects a return value from the current thread, then it is the instance that returned 0 from fork that must still prove that return value.*/
void(...) abort = #211; /*Kills the current thread, returning to the engine. If the engine expected you to return a value, you can pass one to the abort call.*/
//FTE_MVD_PLAYBACK
//no longer supported.
//FTE_NPCCHAT
//builtin chat
//not documented.
//FTE_QC_CHECKPVS
//idea: Spike, Urre
//builtin definitions:
float checkpvs(vector viewpos, entity viewee) = #240;
//description:
//returns true if viewee can be seen from viewpos according to PVS data
//note that viewpos is cached, and you'll get better results if you keep that argument the same when calling multiple times.
//FTE_QC_MATCHCLIENTNAME
//Given a rough client name, attempts to find a client with the matching name.
//Can find multiple (if * is used, for example).
//match is the name to match against
//if matchnum is specified, 0 is the first, 1 is the second.
//if matchnum is not present (only 1 arg) then only one client will be returned, and it'll fail if there were more matches.
entity(string match, float matchnum) matchclients = #241;
entity(string match) matchclient = #241;
//FTE_QC_PAUSED
//deprecated, use ZQ_QC_PAUSED instead.
//FTE_QC_SENDPACKET
//document me!
/*
sendpacket
*/
//FTE_QC_TRACETRIGGER
//idea: often
//Adds two new sorts of traces
//.flags flags:
float FL_FINDABLE_NONSOLID = 16384; //Affects findradius. SOLID_NOT entities may be returned if this is set in QW mods.
//'nomonsters' flags for traceline:
float MOVE_TRIGGERS = 16; //also hits triggers with the FL_FINDABLE_NONSOLID flag. Still hits everything else.
float MOVE_EVERYTHING = 32; //hits SOLID_NOT entites and SOLID_TRIGGER, so long as they have FL_FINDABLE_NONSOLID set. Still hits everything else.
//FTE_SOLID_LADDER
//acts like SOLID_TRIGGER, except that players within the trigger will have their movement changed so they act as if on a ladder. Gravity is removed.
float SOLID_LADDER = 20;
//FTE_SQL
//document me!
/*
sqlconnect
sqldisconnect
sqlopenquery
sqlclosequery
sqlreadfield
sqlerror
sqlescape
sqlversion
sqlreadfloat
*/
//FTE_STRINGS
//idea: many
//darkplaces implementation: KrimZon
//builtin definitions:
float(string str, string sub, float startpos) strstrofs = #221; // returns the offset into a string of the matching text, or -1 if not found, case sensitive
float(string str, float ofs) str2chr = #222; // returns the character at the specified offset as an integer, or 0 if an invalid index, or byte value - 256 if the engine supports UTF8 and the byte is part of an extended character
string(float c, ...) chr2str = #223; // returns a string representing the character given, if the engine supports UTF8 this may be a multi-byte sequence (length may be more than 1) for characters over 127.
string(float ccase, float calpha, float cnum, string s, ...) strconv = #224; // reformat a string with special color characters in the font, DO NOT USE THIS ON UTF8 ENGINES (if you are lucky they will emit ^4 and such color codes instead), the parameter values are 0=same/1=lower/2=upper for ccase, 0=same/1=white/2=red/5=alternate/6=alternate-alternate for redalpha, 0=same/1=white/2=red/3=redspecial/4=whitespecial/5=alternate/6=alternate-alternate for rednum.
string(float chars, string s, ...) strpad = #225; // pad string with spaces to a specified length, < 0 = left padding, > 0 = right padding
string(string info, string key, string value, ...) infoadd = #226; // sets or adds a key/value pair to an infostring - note: forbidden characters are \ and "
string(string info, string key) infoget = #227; // gets a key/value pair in an infostring, returns value or null if not found
float(string s1, string s2, float len) strncmp = #228; // compare two strings up to the specified number of characters, if their length differs and is within the specified limit the result will be negative, otherwise it is the difference in value of their first non-matching character.
float(string s1, string s2) strcasecmp = #229; // compare two strings with case-insensitive matching, characters a-z are considered equivalent to the matching A-Z character, no other differences, and this does not consider special characters equal even if they look similar
float(string s1, string s2, float len) strncasecmp = #230; // same as strcasecmp but with a length limit, see strncmp
//string(string s, float start, float length) substring = #116; // see note below
//description:
//various string manipulation functions
//note: substring also exists in FRIK_FILE but this extension adds negative start and length as valid cases (see note above), substring is consistent with the php 5.2.0 substr function (not 5.2.3 behavior)
//substring returns a section of a string as a tempstring, if given negative
// start the start is measured back from the end of the string, if given a
// negative length the length is the offset back from the end of the string to
// stop at, rather than being relative to start, if start is negative and
// larger than length it is treated as 0.
// examples of substring:
// substring("blah", -3, 3) returns "lah"
// substring("blah", 3, 3) returns "h"
// substring("blah", -10, 3) returns "bla"
// substring("blah", -10, -3) returns "b"
//FTE_SV_REENTER
//If ClientReEnter is defined, it will be called instead of the ClientConnect/PutClientInServer pair at map start.
#ifdef CSQC
//void() ClientReEnter;
//self is defined to be the player entity with a copy of all saved fields from the previous map. This does not affect initial spawning.
#endif
//FTE_TE_STANDARDEFFECTBUILTINS
//equivelent to DP_TE_STANDARDEFFECTBUILTINS, but applicable to QuakeWorld instead.
//document me!
/*
te_gunshot
te_spike
te_superspike
te_explosion
te_tarexplosion
te_wizspike
te_knightspike
te_lavasplash
te_teleport
te_lightning1
te_lightning2
te_lightning3
te_lightningblood
te_bloodqw
*/
void(vector org) te_gunshot = #418;
void(vector org) te_spike = #419;
void(vector org) te_superspike = #420;
void(vector org) te_explosion = #421;
void(vector org) te_tarexplosion = #420;
void(vector org) te_wizspike = #423;
void(vector org) te_knightspike = #424;
void(vector org) te_lavasplash = #425;
void(vector org) te_teleport = #426;
void(entity own, vector start, vector end) te_lightning1 = #428;
void(entity own, vector start, vector end) te_lightning2 = #429;
void(entity own, vector start, vector end) te_lightning3 = #430;
void(vector org, float count) te_bloodqw = #239;
void(vector org) te_lightningblood = #219;