diff --git a/engine/Makefile b/engine/Makefile index 8929e51f..8bd27247 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -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 \ diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 81a699f3..4b43fad9 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -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) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 31a43c80..d390199e 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -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); diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 6072ef43..ba270edd 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -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); diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c new file mode 100644 index 00000000..426a69c4 --- /dev/null +++ b/engine/client/r_surf.c @@ -0,0 +1,2724 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_surf.c: surface-related refresh code + +#include "quakedef.h" +#if defined(GLQUAKE) || defined(D3DQUAKE) +#include "glquake.h" +#include "shader.h" +#include "renderque.h" +#include + +extern cvar_t gl_bump; + +static vec3_t modelorg; /*set before recursively entering the visible surface finder*/ +static qbyte areabits[MAX_Q2MAP_AREAS/8]; + +model_t *currentmodel; + + +int lightmap_bytes; // 1, 3 or 4 + +texid_t *lightmap_textures; +texid_t *deluxmap_textures; + +#define MAX_LIGHTMAP_SIZE LMBLOCK_WIDTH + +vec3_t blocknormals[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE]; +unsigned blocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE]; +#ifdef PEXT_LIGHTSTYLECOL +unsigned greenblklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE]; +unsigned blueblklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE]; +#endif + +lightmapinfo_t **lightmap; +int numlightmaps; + +mleaf_t *r_vischain; // linked list of visible leafs + +extern cvar_t r_stains; +extern cvar_t r_loadlits; +extern cvar_t r_stainfadetime; +extern cvar_t r_stainfadeammount; + +int Surf_LightmapShift (model_t *model) +{ + extern cvar_t gl_overbright_all, gl_lightmap_shift; + + if (gl_overbright_all.ival || (model->engineflags & MDLF_NEEDOVERBRIGHT)) + return bound(0, gl_lightmap_shift.ival, 2); + return 0; +} + +//radius, x y z, r g b +void Surf_StainSurf (msurface_t *surf, float *parms) +{ + int sd, td; + float dist, rad, minlight; + float change; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + float amm; + int lim; + mtexinfo_t *tex; + stmap *stainbase; + + lim = 255 - (r_stains.value*255); + +#define stain(x) \ + change = stainbase[(s)*3+x] + amm*parms[4+x]; \ + stainbase[(s)*3+x] = bound(lim, change, 255); + + if (surf->lightmaptexturenum < 0) + return; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + stainbase = lightmap[surf->lightmaptexturenum]->stainmaps; + stainbase += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * 3; + + rad = *parms; + dist = DotProduct ((parms+1), surf->plane->normal) - surf->plane->dist; + rad -= fabs(dist); + minlight = 0; + if (rad < minlight) //not hit + return; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = (parms+1)[i] - surf->plane->normal[i]*dist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + { + amm = (rad - dist); + stain(0); + stain(1); + stain(2); + + surf->stained = true; + } + } + stainbase += 3*LMBLOCK_WIDTH; + } + + if (surf->stained) + surf->cached_dlight=-1; +} + +//combination of R_AddDynamicLights and R_MarkLights +/* +static void Surf_StainNode (mnode_t *node, float *parms) +{ + mplane_t *splitplane; + float dist; + msurface_t *surf; + int i; + + if (node->contents < 0) + return; + + splitplane = node->plane; + dist = DotProduct ((parms+1), splitplane->normal) - splitplane->dist; + + if (dist > (*parms)) + { + Surf_StainNode (node->children[0], parms); + return; + } + if (dist < (-*parms)) + { + Surf_StainNode (node->children[1], parms); + return; + } + +// mark the polygons + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags&~(SURF_DONTWARP|SURF_PLANEBACK)) + continue; + Surf_StainSurf(surf, parms); + } + + Surf_StainNode (node->children[0], parms); + Surf_StainNode (node->children[1], parms); +} +*/ + +void Surf_AddStain(vec3_t org, float red, float green, float blue, float radius) +{ + physent_t *pe; + int i; + + float parms[7]; + if (!cl.worldmodel || cl.worldmodel->needload || r_stains.value <= 0) + return; + parms[0] = radius; + parms[1] = org[0]; + parms[2] = org[1]; + parms[3] = org[2]; + parms[4] = red; + parms[5] = green; + parms[6] = blue; + + + cl.worldmodel->funcs.StainNode(cl.worldmodel->nodes+cl.worldmodel->hulls[0].firstclipnode, parms); + + //now stain bsp models other than world. + + for (i=1 ; i< pmove.numphysent ; i++) //0 is world... + { + pe = &pmove.physents[i]; + if (pe->model && pe->model->surfaces == cl.worldmodel->surfaces) + { + parms[1] = org[0] - pe->origin[0]; + parms[2] = org[1] - pe->origin[1]; + parms[3] = org[2] - pe->origin[2]; + + if (pe->angles[0] || pe->angles[1] || pe->angles[2]) + { + vec3_t f, r, u, temp; + AngleVectors(pe->angles, f, r, u); + VectorCopy((parms+1), temp); + parms[1] = DotProduct(temp, f); + parms[2] = -DotProduct(temp, r); + parms[3] = DotProduct(temp, u); + } + + + pe->model->funcs.StainNode(pe->model->nodes+pe->model->hulls[0].firstclipnode, parms); + } + } +} + +void Surf_WipeStains(void) +{ + int i; + for (i = 0; i < numlightmaps; i++) + { + if (!lightmap[i]) + break; + memset(lightmap[i]->stainmaps, 255, sizeof(lightmap[i]->stainmaps)); + } +} + +void Surf_LessenStains(void) +{ + int i; + msurface_t *surf; + + int smax, tmax; + int s, t; + stmap *stain; + int stride; + int ammount; + int limit; + + static float time; + + if (!r_stains.value) + return; + + time += host_frametime; + if (time < r_stainfadetime.value) + return; + time-=r_stainfadetime.value; + + ammount = r_stainfadeammount.value; + limit = 255 - ammount; + + surf = cl.worldmodel->surfaces; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->stained) + { + surf->cached_dlight=-1;//nice hack here... + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + stain = lightmap[surf->lightmaptexturenum]->stainmaps; + stain += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * 3; + + stride = (LMBLOCK_WIDTH-smax)*3; + + surf->stained = false; + + smax*=3; + + for (t = 0 ; tstained=true; + } + else //reset to 255 + *stain = 255; + + stain++; + } + } + } + } +} + +/* +=============== +R_AddDynamicLights +=============== +*/ +static void Surf_AddDynamicLights (msurface_t *surf) +{ + int lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + float a; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=rtlights_first; lnumdlightbits & (1<plane->normal) - + surf->plane->dist; + rad -= fabs(dist); + minlight = cl_dlights[lnum].minlight; + if (rad < minlight) + continue; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = cl_dlights[lnum].origin[i] - + surf->plane->normal[i]*dist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + a = 256*(cl_dlights[lnum].color[0]*1.5 + cl_dlights[lnum].color[1]*2.95 + cl_dlights[lnum].color[2]*0.55); + + for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + blocklights[t*smax + s] += (rad - dist)*a; + } + } + } +} + +static void Surf_AddDynamicLightNorms (msurface_t *surf) +{ + int lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + float a; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=rtlights_first; lnumdlightbits & (1<plane->normal) - + surf->plane->dist; + rad -= fabs(dist); + minlight = cl_dlights[lnum].minlight; + if (rad < minlight) + continue; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = cl_dlights[lnum].origin[i] - + surf->plane->normal[i]*dist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + a = 256*(cl_dlights[lnum].color[0]*1.5 + cl_dlights[lnum].color[1]*2.95 + cl_dlights[lnum].color[2]*0.55); + + for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + { +// blocknormals[t*smax + s][0] -= (rad - dist)*(impact[0]-local[0])/8192.0; +// blocknormals[t*smax + s][1] -= (rad - dist)*(impact[1]-local[1])/8192.0; + blocknormals[t*smax + s][2] += 0.5*blocknormals[t*smax + s][2]*(rad - dist)/256; + } + } + } + } +} + +#ifdef PEXT_LIGHTSTYLECOL +static void Surf_AddDynamicLightsColours (msurface_t *surf) +{ + int lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; +// float temp; + float r, g, b; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=rtlights_first; lnumdlightbits & (1<plane->normal) - + surf->plane->dist; + rad -= fabs(dist); + minlight = cl_dlights[lnum].minlight; + if (rad < minlight) + continue; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = cl_dlights[lnum].origin[i] - + surf->plane->normal[i]*dist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + r = cl_dlights[lnum].color[0]*3*256; + g = cl_dlights[lnum].color[1]*3*256; + b = cl_dlights[lnum].color[2]*3*256; + +/* if (cl_dlights[lnum].type == 1) //a wierd effect. + { + for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + { + blocklights[t*smax + s] += 2*sin(dist/10+cl.time*20)*(rad - dist)*256 * cl_dlights[lnum].colour[0]*3; + greenblklights[t*smax + s] += 2*sin(M_PI/3+dist/10+cl.time*20)*(rad - dist)*256 * cl_dlights[lnum].colour[1]*3; + blueblklights[t*smax + s] += 2*sin(2*M_PI/3+dist/10+cl.time*20)*(rad - dist)*256 * cl_dlights[lnum].colour[2]*3; + } + } + } + } + else + { +*/ for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + { + blocklights[t*smax + s] += (rad - dist)*r; + greenblklights[t*smax + s] += (rad - dist)*g; + blueblklights[t*smax + s] += (rad - dist)*b; + } + } + } +// } + } +} +#endif + + + +static void Surf_BuildDeluxMap (msurface_t *surf, qbyte *dest) +{ + int smax, tmax; + int i, j, size; + qbyte *lightmap; + qbyte *deluxmap; + unsigned scale; + int maps; + float intensity; + vec_t *bnorm; + vec3_t temp; + + int stride = LMBLOCK_WIDTH*3; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + lightmap = surf->samples; + + // set to full bright if no light data + if (!currentmodel->deluxdata) + { + for (i=0 ; iorientation[2][0]; + blocknormals[i][1] = 0.8;//surf->orientation[2][1]; + blocknormals[i][2] = 1;//surf->orientation[2][2]; + } + goto store; + } + + if (currentmodel->engineflags & MDLF_RGBLIGHTING) + deluxmap = surf->samples - currentmodel->lightdata + currentmodel->deluxdata; + else + deluxmap = (surf->samples - currentmodel->lightdata)*3 + currentmodel->deluxdata; + + +// clear to no light + for (i=0 ; iengineflags & MDLF_RGBLIGHTING) + { + deluxmap = surf->samples - currentmodel->lightdata + currentmodel->deluxdata; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + for (i=0 ; isamples - currentmodel->lightdata)*3 + currentmodel->deluxdata; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + for (i=0 ; idlightframe == r_framecount) +// GLR_AddDynamicLightNorms (surf); + +// bound, invert, and shift + + stride -= smax*3; + + bnorm = blocknormals[0]; + for (i=0 ; isamples && currentmodel->lightdata) + return; + + shift += 7; // increase to base value + surf->cached_dlight = (surf->dlightframe == r_framecount); + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + lightmap = surf->samples; + + if (size > MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE) + { //fixme: fill in? + Con_Printf("Lightmap too large\n"); + return; + } + + if (currentmodel->deluxdata) + Surf_BuildDeluxMap(surf, deluxdest); + + +#ifdef PEXT_LIGHTSTYLECOL + if (lightmap_bytes == 4 || lightmap_bytes == 3) + { + // set to full bright if no light data + if (r_fullbright.value>0) //not qw + { + for (i=0 ; idlightframe == r_framecount) + Surf_AddDynamicLightsColours (surf); + } + goto store; + } + if (!currentmodel->lightdata) + { + for (i=0 ; idlightframe == r_framecount) + Surf_AddDynamicLightsColours (surf); + goto store; + } + +// clear to no light + t = r_ambient.value*255; + for (i=0 ; ifromgame == fg_quake3) //rgb + { + /* for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) //no light styles in q3 apparently. + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; + } + */ + for (i = 0; i < tmax; i++) //q3 maps store their light in a block fashion, q1/q2/hl store it in a linear fashion. + { + for (j = 0; j < smax; j++) + { + blocklights[i*smax+j] = 255*lightmap[(i*LMBLOCK_WIDTH+j)*3]; + greenblklights[i*smax+j] = 255*lightmap[(i*LMBLOCK_WIDTH+j)*3+1]; + blueblklights[i*smax+j] = 255*lightmap[(i*LMBLOCK_WIDTH+j)*3+2]; + } + } +// memset(blocklights, 255, sizeof(blocklights)); + } + else if (currentmodel->engineflags & MDLF_RGBLIGHTING) //rgb + { + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; + + + if (cl_lightstyle[surf->styles[maps]].colour == 7) //hopefully a faster alternative. + { + for (i=0 ; istyles[maps]].colour & 1) + for (i=0 ; istyles[maps]].colour & 2) + for (i=0 ; istyles[maps]].colour & 4) + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; + + if (cl_lightstyle[surf->styles[maps]].colour == 7) //hopefully a faster alternative. + { + for (i=0 ; istyles[maps]].colour & 1) + for (i=0 ; istyles[maps]].colour & 2) + for (i=0 ; istyles[maps]].colour & 4) + for (i=0 ; idlightframe == r_framecount) + Surf_AddDynamicLightsColours (surf); + } + else + { +#endif + // set to full bright if no light data + if (r_fullbright.value || !currentmodel->lightdata) + { + for (i=0 ; iengineflags & MDLF_RGBLIGHTING) //rgb + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]/3; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; + for (i=0 ; idlightframe == r_framecount) + Surf_AddDynamicLights (surf); +#ifdef PEXT_LIGHTSTYLECOL + } +#endif + +// bound, invert, and shift +store: +#ifdef INVERTLIGHTMAPS + switch (gl_lightmap_format) + { +#ifdef PEXT_LIGHTSTYLECOL + case GL_RGBA: + stride -= (smax<<2); + bl = blocklights; + blg = greenblklights; + blb = blueblklights; + + if (!r_stains.value) + isstained = false; + else + isstained = surf->stained; + +/* if (!gl_lightcomponantreduction.value) + { + for (i=0 ; i>= 7; + if (t > 255) + dest[0] = 0; + else if (t < 0) + dest[0] = 256; + else + dest[0] = (255-t); + + t = *blg++; + t >>= 7; + if (t > 255) + dest[1] = 0; + else if (t < 0) + dest[1] = 256; + else + dest[1] = (255-t); + + t = *blb++; + t >>= 7; + if (t > 255) + dest[2] = 0; + else if (t < 0) + dest[2] = 256; + else + dest[2] = (255-t); + + dest[3] = 0;//(dest[0]+dest[1]+dest[2])/3; + dest += 4; + } + } + } + else +*/ { + stmap *stain; + for (i=0 ; i>= shift; + g >>= shift; + b >>= shift; + + if (isstained) // merge in stain + { + r = (127+r*(*stain++)) >> 8; + g = (127+g*(*stain++)) >> 8; + b = (127+b*(*stain++)) >> 8; + } + + cr = 0; + cg = 0; + cb = 0; + + if (r > 255) //ak too much red + { + cr -= (255-r)/2; + cg += (255-r)/4; //reduce it, and indicate to drop the others too. + cb += (255-r)/4; + r = 255; + } +// else if (r < 0) +// r = 0; + + if (g > 255) + { + cr += (255-g)/4; + cg -= (255-g)/2; + cb += (255-g)/4; + g = 255; + } +// else if (g < 0) +// g = 0; + + if (b > 255) + { + cr += (255-b)/4; + cg += (255-b)/4; + cb -= (255-b)/2; + b = 255; + } +// else if (b < 0) +// b = 0; + //* + if ((r+cr) > 255) + dest[0] = 0; //inverse lighting + else if ((r+cr) < 0) + dest[0] = 255; + else + dest[0] = 255-(r+cr); + + if ((g+cg) > 255) + dest[1] = 0; + else if ((g+cg) < 0) + dest[1] = 255; + else + dest[1] = 255-(g+cg); + + if ((b+cb) > 255) + dest[2] = 0; + else if ((b+cb) < 0) + dest[2] = 255; + else + dest[2] = 255-(b+cb); +/*/ + if ((r+cr) > 255) + dest[0] = 255; //non-inverse lighting + else if ((r+cr) < 0) + dest[0] = 0; + else + dest[0] = (r+cr); + + if ((g+cg) > 255) + dest[1] = 255; + else if ((g+cg) < 0) + dest[1] = 0; + else + dest[1] = (g+cg); + + if ((b+cb) > 255) + dest[2] = 255; + else if ((b+cb) < 0) + dest[2] = 0; + else + dest[2] = (b+cb); +*/ + + + + dest[3] = (dest[0]+dest[1]+dest[2])/3; //alpha?!?! + dest += 4; + } + } + } + break; + + case GL_RGB: + stride -= smax*3; + bl = blocklights; + blg = greenblklights; + blb = blueblklights; + + if (!r_stains.value) + isstained = false; + else + isstained = surf->stained; + +/* if (!gl_lightcomponantreduction.value) + { + for (i=0 ; i>= 7; + if (t > 255) + dest[0] = 0; + else if (t < 0) + dest[0] = 256; + else + dest[0] = (255-t); + + t = *blg++; + t >>= 7; + if (t > 255) + dest[1] = 0; + else if (t < 0) + dest[1] = 256; + else + dest[1] = (255-t); + + t = *blb++; + t >>= 7; + if (t > 255) + dest[2] = 0; + else if (t < 0) + dest[2] = 256; + else + dest[2] = (255-t); + + dest += 3; + } + } + } + else +*/ { + stmap *stain; + for (i=0 ; i>= shift; + g >>= shift; + b >>= shift; + + if (isstained) // merge in stain + { + r = (127+r*(*stain++)) >> 8; + g = (127+g*(*stain++)) >> 8; + b = (127+b*(*stain++)) >> 8; + } + + cr = 0; + cg = 0; + cb = 0; + + if (r > 255) //ak too much red + { + cr -= (255-r)/2; + cg += (255-r)/4; //reduce it, and indicate to drop the others too. + cb += (255-r)/4; + r = 255; + } +// else if (r < 0) +// r = 0; + + if (g > 255) + { + cr += (255-g)/4; + cg -= (255-g)/2; + cb += (255-g)/4; + g = 255; + } +// else if (g < 0) +// g = 0; + + if (b > 255) + { + cr += (255-b)/4; + cg += (255-b)/4; + cb -= (255-b)/2; + b = 255; + } +// else if (b < 0) +// b = 0; + //* + if ((r+cr) > 255) + dest[0] = 0; //inverse lighting + else if ((r+cr) < 0) + dest[0] = 255; + else + dest[0] = 255-(r+cr); + + if ((g+cg) > 255) + dest[1] = 0; + else if ((g+cg) < 0) + dest[1] = 255; + else + dest[1] = 255-(g+cg); + + if ((b+cb) > 255) + dest[2] = 0; + else if ((b+cb) < 0) + dest[2] = 255; + else + dest[2] = 255-(b+cb); +/*/ + if ((r+cr) > 255) + dest[0] = 255; //non-inverse lighting + else if ((r+cr) < 0) + dest[0] = 0; + else + dest[0] = (r+cr); + + if ((g+cg) > 255) + dest[1] = 255; + else if ((g+cg) < 0) + dest[1] = 0; + else + dest[1] = (g+cg); + + if ((b+cb) > 255) + dest[2] = 255; + else if ((b+cb) < 0) + dest[2] = 0; + else + dest[2] = (b+cb); +// */ + dest += 3; + } + } + } + break; +#else + case GL_RGBA: + stride -= (smax<<2); + bl = blocklights; + for (i=0 ; i>= shift; + if (t > 255) + t = 255; + dest[3] = 255-t; + dest += 4; + } + } + break; +#endif + case GL_ALPHA: + case GL_LUMINANCE: + case GL_INTENSITY: + bl = blocklights; + for (i=0 ; i>= shift; + if (t > 255) + t = 255; + dest[j] = 255-t; + } + } + break; + default: + Sys_Error ("Bad lightmap format"); + } +#else + switch (lightmap_bytes) + { +#ifdef PEXT_LIGHTSTYLECOL + case 4: + stride -= (smax<<2); + bl = blocklights; + blg = greenblklights; + blb = blueblklights; + + if (!r_stains.value) + isstained = false; + else + isstained = surf->stained; + +/* if (!gl_lightcomponantreduction.value) + { + for (i=0 ; i>= 7; + if (t > 255) + dest[0] = 0; + else if (t < 0) + dest[0] = 256; + else + dest[0] = (255-t); + + t = *blg++; + t >>= 7; + if (t > 255) + dest[1] = 0; + else if (t < 0) + dest[1] = 256; + else + dest[1] = (255-t); + + t = *blb++; + t >>= 7; + if (t > 255) + dest[2] = 0; + else if (t < 0) + dest[2] = 256; + else + dest[2] = (255-t); + + dest[3] = 0;//(dest[0]+dest[1]+dest[2])/3; + dest += 4; + } + } + } + else +*/ { + stmap *stain; + for (i=0 ; i>= shift; + g >>= shift; + b >>= shift; + + if (isstained) // merge in stain + { + r = (127+r*(*stain++)) >> 8; + g = (127+g*(*stain++)) >> 8; + b = (127+b*(*stain++)) >> 8; + } + + cr = 0; + cg = 0; + cb = 0; + + if (r > 255) //ak too much red + { + cr -= (255-r)/2; + cg += (255-r)/4; //reduce it, and indicate to drop the others too. + cb += (255-r)/4; + r = 255; + } +// else if (r < 0) +// r = 0; + + if (g > 255) + { + cr += (255-g)/4; + cg -= (255-g)/2; + cb += (255-g)/4; + g = 255; + } +// else if (g < 0) +// g = 0; + + if (b > 255) + { + cr += (255-b)/4; + cg += (255-b)/4; + cb -= (255-b)/2; + b = 255; + } +// else if (b < 0) +// b = 0; + //* + if ((r+cr) > 255) + dest[0] = 0; //inverse lighting + else if ((r+cr) < 0) + dest[0] = 255; + else + dest[0] = 255-(r+cr); + + if ((g+cg) > 255) + dest[1] = 0; + else if ((g+cg) < 0) + dest[1] = 255; + else + dest[1] = 255-(g+cg); + + if ((b+cb) > 255) + dest[2] = 0; + else if ((b+cb) < 0) + dest[2] = 255; + else + dest[2] = 255-(b+cb); +/*/ + if ((r+cr) > 255) + dest[0] = 255; //non-inverse lighting + else if ((r+cr) < 0) + dest[0] = 0; + else + dest[0] = (r+cr); + + if ((g+cg) > 255) + dest[1] = 255; + else if ((g+cg) < 0) + dest[1] = 0; + else + dest[1] = (g+cg); + + if ((b+cb) > 255) + dest[2] = 255; + else if ((b+cb) < 0) + dest[2] = 0; + else + dest[2] = (b+cb); +*/ + + + + dest[3] = (dest[0]+dest[1]+dest[2])/3; //alpha?!?! + dest += 4; + } + } + } + break; + + case 3: + stride -= smax*3; + bl = blocklights; + blg = greenblklights; + blb = blueblklights; + + if (!r_stains.value) + isstained = false; + else + isstained = surf->stained; + +/* if (!gl_lightcomponantreduction.value) + { + for (i=0 ; i>= 7; + if (t > 255) + dest[0] = 255; + else if (t < 0) + dest[0] = 0; + else + dest[0] = t; + + t = *blg++; + t >>= 7; + if (t > 255) + dest[1] = 255; + else if (t < 0) + dest[1] = 0; + else + dest[1] = t; + + t = *blb++; + t >>= 7; + if (t > 255) + dest[2] = 255; + else if (t < 0) + dest[2] = 0; + else + dest[2] = t; + + dest += 3; + } + } + } + else +*/ { + stmap *stain; + for (i=0 ; i>= shift; + g >>= shift; + b >>= shift; + + if (isstained) // merge in stain + { + r = (127+r*(*stain++)) >> 8; + g = (127+g*(*stain++)) >> 8; + b = (127+b*(*stain++)) >> 8; + } + + cr = 0; + cg = 0; + cb = 0; + + if (r > 255) //ak too much red + { + cr -= (255-r)/2; + cg += (255-r)/4; //reduce it, and indicate to drop the others too. + cb += (255-r)/4; + r = 255; + } +// else if (r < 0) +// r = 0; + + if (g > 255) + { + cr += (255-g)/4; + cg -= (255-g)/2; + cb += (255-g)/4; + g = 255; + } +// else if (g < 0) +// g = 0; + + if (b > 255) + { + cr += (255-b)/4; + cg += (255-b)/4; + cb -= (255-b)/2; + b = 255; + } +// else if (b < 0) +// b = 0; + //* + if ((r+cr) > 255) + dest[0] = 255; //inverse lighting + else if ((r+cr) < 0) + dest[0] = 0; + else + dest[0] = (r+cr); + + if ((g+cg) > 255) + dest[1] = 255; + else if ((g+cg) < 0) + dest[1] = 0; + else + dest[1] = (g+cg); + + if ((b+cb) > 255) + dest[2] = 255; + else if ((b+cb) < 0) + dest[2] = 0; + else + dest[2] = (b+cb); +/*/ + if ((r+cr) > 255) + dest[0] = 255; //non-inverse lighting + else if ((r+cr) < 0) + dest[0] = 0; + else + dest[0] = (r+cr); + + if ((g+cg) > 255) + dest[1] = 255; + else if ((g+cg) < 0) + dest[1] = 0; + else + dest[1] = (g+cg); + + if ((b+cb) > 255) + dest[2] = 255; + else if ((b+cb) < 0) + dest[2] = 0; + else + dest[2] = (b+cb); +// */ + dest += 3; + } + } + } + break; +#else + case 4: + stride -= (smax<<2); + bl = blocklights; + for (i=0 ; i>= shift; + if (t > 255) + t = 255; + dest[3] = t; + dest += 4; + } + } + break; +#endif + case 1: + bl = blocklights; + for (i=0 ; i>= shift; + if (t > 255) + t = 255; + dest[j] = t; + } + } + break; + default: + Sys_Error ("Bad lightmap format"); + } +#endif +} + + +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ + +/* +================ +R_RenderDynamicLightmaps +Multitexture +================ +*/ +void Surf_RenderDynamicLightmaps (msurface_t *fa, int shift) +{ + qbyte *base, *luxbase; + stmap *stainbase; + int maps; + glRect_t *theRect; + int smax, tmax; + + if (!fa->mesh) + return; + + if (fa->lightmaptexturenum<0) + return; + + if (fa->flags & ( SURF_DRAWSKY | SURF_DRAWTURB) ) + return; + + if (fa->texinfo->flags & (TI_SKY|TI_TRANS33|TI_TRANS66|TI_WARP)) + return; + + if (fa->texinfo->flags & (TEX_SPECIAL)) + { + if (cl.worldmodel->fromgame == fg_halflife) + return; //some textures do this. + } + +// fa->polys->chain = lightmap[fa->lightmaptexturenum]->polys; +// lightmap[fa->lightmaptexturenum]->polys = fa->polys; + + // check for lightmap modification +// if (cl.worldmodel->fromgame != fg_quake3) //no lightstyles on q3 maps + { + for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ; + maps++) + if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] + #ifdef PEXT_LIGHTSTYLECOL + || cl_lightstyle[fa->styles[maps]].colour != fa->cached_colour[maps] + #endif + ) + goto dynamic; + } + + if (fa->dlightframe == r_framecount // dynamic this frame + || fa->cached_dlight) // dynamic previously + { + RSpeedLocals(); +dynamic: + RSpeedRemark(); + + lightmap[fa->lightmaptexturenum]->modified = true; + + smax = (fa->extents[0]>>4)+1; + tmax = (fa->extents[1]>>4)+1; + + theRect = &lightmap[fa->lightmaptexturenum]->rectchange; + if (fa->light_t < theRect->t) { + if (theRect->h) + theRect->h += theRect->t - fa->light_t; + theRect->t = fa->light_t; + } + if (fa->light_s < theRect->l) { + if (theRect->w) + theRect->w += theRect->l - fa->light_s; + theRect->l = fa->light_s; + } + if ((theRect->w + theRect->l) < (fa->light_s + smax)) + theRect->w = (fa->light_s-theRect->l)+smax; + if ((theRect->h + theRect->t) < (fa->light_t + tmax)) + theRect->h = (fa->light_t-theRect->t)+tmax; + + if (gl_bump.ival) + { + lightmap[fa->lightmaptexturenum]->deluxmodified = true; + theRect = &lightmap[fa->lightmaptexturenum]->deluxrectchange; + if (fa->light_t < theRect->t) { + if (theRect->h) + theRect->h += theRect->t - fa->light_t; + theRect->t = fa->light_t; + } + if (fa->light_s < theRect->l) { + if (theRect->w) + theRect->w += theRect->l - fa->light_s; + theRect->l = fa->light_s; + } + + if ((theRect->w + theRect->l) < (fa->light_s + smax)) + theRect->w = (fa->light_s-theRect->l)+smax; + if ((theRect->h + theRect->t) < (fa->light_t + tmax)) + theRect->h = (fa->light_t-theRect->t)+tmax; + + luxbase = lightmap[fa->lightmaptexturenum]->deluxmaps; + luxbase += fa->light_t * LMBLOCK_WIDTH * 3 + fa->light_s * 3; + } + else + luxbase = NULL; + + + base = lightmap[fa->lightmaptexturenum]->lightmaps; + base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes; + stainbase = lightmap[fa->lightmaptexturenum]->stainmaps; + stainbase += (fa->light_t * LMBLOCK_WIDTH + fa->light_s) * 3; + Surf_BuildLightMap (fa, base, luxbase, stainbase, shift); + + RSpeedEnd(RSPEED_DYNAMIC); + } +} + +/* +============================================================= + + WORLD MODEL + +============================================================= +*/ + +static qbyte *R_MarkLeafSurfaces_Q1 (void) +{ + qbyte *vis; + mleaf_t *leaf; + int i, j; + msurface_t *surf; + int shift; + + vis = R_CalcVis_Q1(); + + for (i=0 ; inumleafs ; i++) + { + if (vis[i>>3] & (1<<(i&7))) + { + leaf = (mleaf_t *)&cl.worldmodel->leafs[i+1]; + + if (R_CullBox (leaf->minmaxs, leaf->minmaxs+3)) + continue; + leaf->visframe = r_visframecount; + + for (j = 0; j < leaf->nummarksurfaces; j++) + { + surf = leaf->firstmarksurface[j]; + if (surf->visframe == r_visframecount) + continue; + surf->visframe = r_visframecount; + + *surf->mark = surf; + } + + //deal with static ents. + if (leaf->efrags) + R_StoreEfrags (&leaf->efrags); + } + } + + { + texture_t *tex; + + shift = Surf_LightmapShift(cl.worldmodel); + + for (i = 0; i < cl.worldmodel->numtextures; i++) + { + tex = cl.worldmodel->textures[i]; + if (!tex) + continue; + for (j = 0; j < tex->vbo.meshcount; j++) + { + surf = tex->vbo.meshlist[j]; + if (surf) + { + Surf_RenderDynamicLightmaps (surf, shift); + + tex->vbo.meshlist[j] = NULL; + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + } + } + } + return vis; +} + +/* +================ +R_RecursiveWorldNode +================ +*/ +static void Surf_RecursiveWorldNode (mnode_t *node, unsigned int clipflags) +{ + int c, side, clipped; + mplane_t *plane, *clipplane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + double dot; + int shift; + +start: + + if (node->contents == Q1CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + + for (c = 0, clipplane = frustum; c < 4; c++, clipplane++) + { + if (!(clipflags & (1 << c))) + continue; // don't need to clip against it + + clipped = BOX_ON_PLANE_SIDE (node->minmaxs, node->minmaxs + 3, clipplane); + if (clipped == 2) + return; + else if (clipped == 1) + clipflags -= (1<contents < 0) + { + pleaf = (mleaf_t *)node; + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark++)->visframe = r_framecount; + } while (--c); + } + + // deal with model fragments in this leaf + if (pleaf->efrags) + R_StoreEfrags (&pleaf->efrags); + return; + } + +// node is just a decision point, so go down the apropriate sides + +// find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + side = 0; + else + side = 1; + +// recurse down the children, front side first + Surf_RecursiveWorldNode (node->children[side], clipflags); + +// draw stuff + c = node->numsurfaces; + + if (c) + { + surf = cl.worldmodel->surfaces + node->firstsurface; + + shift = Surf_LightmapShift(cl.worldmodel); + + if (dot < 0 -BACKFACE_EPSILON) + side = SURF_PLANEBACK; + else if (dot > BACKFACE_EPSILON) + side = 0; + { + for ( ; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + if (((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))) + continue; // wrong side + + Surf_RenderDynamicLightmaps (surf, shift); + // if sorting by texture, just store it out + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + } + } + +// recurse down the back side + //GLR_RecursiveWorldNode (node->children[!side], clipflags); + node = node->children[!side]; + goto start; +} + +#ifdef Q2BSPS +static void Surf_RecursiveQ2WorldNode (mnode_t *node) +{ + int c, side; + mplane_t *plane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + double dot; + int shift; + + int sidebit; + + if (node->contents == Q2CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + if (R_CullBox (node->minmaxs, node->minmaxs+3)) + return; + +// if a leaf node, draw stuff + if (node->contents != -1) + { + pleaf = (mleaf_t *)node; + + // check for door connected areas +// if (areabits) + { + if (! (areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) ) + return; // not visible + } + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark)->visframe = r_framecount; + mark++; + } while (--c); + } + return; + } + +// node is just a decision point, so go down the apropriate sides + +// find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + { + side = 0; + sidebit = 0; + } + else + { + side = 1; + sidebit = SURF_PLANEBACK; + } + +// recurse down the children, front side first + Surf_RecursiveQ2WorldNode (node->children[side]); + + shift = Surf_LightmapShift(currentmodel); + + // draw stuff + for ( c = node->numsurfaces, surf = currentmodel->surfaces + node->firstsurface; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + if ( (surf->flags & SURF_PLANEBACK) != sidebit ) + continue; // wrong side + + surf->visframe = r_framecount+1;//-1; + + Surf_RenderDynamicLightmaps (surf, shift); + + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + + +// recurse down the back side + Surf_RecursiveQ2WorldNode (node->children[!side]); +} +#endif + +#ifdef Q3BSPS +static void Surf_LeafWorldNode (void) +{ + int i; + int clipflags; + msurface_t **mark, *surf; + mleaf_t *pleaf; + + + int clipped; + mplane_t *clipplane; + + + for (pleaf = r_vischain; pleaf; pleaf = pleaf->vischain) + { + // check for door connected areas +// if (areabits) + { +// if (!(areabits[pleaf->area>>3] & (1<<(pleaf->area&7)))) +// { +// continue; // not visible +// } + } + + clipflags = 15; // 1 | 2 | 4 | 8 +// if (!r_nocull->value) + { + + for (i=0,clipplane=frustum ; i<4 ; i++,clipplane++) + { + clipped = BoxOnPlaneSide (pleaf->minmaxs, pleaf->minmaxs+3, clipplane); + if (clipped == 2) + { + break; + } + else if (clipped == 1) + { + clipflags &= ~(1<nummarksurfaces; + mark = pleaf->firstmarksurface; + + do + { + surf = *mark++; + if (surf->visframe != r_framecount) //sufraces exist in multiple leafs. + { + surf->visframe = r_framecount; + if (surf->mark) + *surf->mark = surf; + /* + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf;# + */ + } + } while (--i); + +// c_world_leafs++; + } + + + + + { + int j; + texture_t *tex; + for (i = 0; i < cl.worldmodel->numtextures; i++) + { + tex = cl.worldmodel->textures[i]; + if (!tex) + continue; + for (j = 0; j < tex->vbo.meshcount; j++) + { + surf = tex->vbo.meshlist[j]; + if (surf) + { + tex->vbo.meshlist[j] = NULL; + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + } + } + } +} +#endif + +static void Surf_ClearChains(void) +{ + int i; + for (i = 0; i < cl.worldmodel->numtextures; i++) + { + if (!cl.worldmodel->textures[i]) + continue; + cl.worldmodel->textures[i]->texturechain = NULL; + cl.worldmodel->textures[i]->texturechain_tail = &cl.worldmodel->textures[i]->texturechain; + } +} + +static void Surf_CleanChains(void) +{ + int i; + model_t *model = cl.worldmodel; + + for (i=0 ; inumtextures ; i++) + { + model->textures[i]->texturechain = NULL; + } +} + +//most of this is a direct copy from gl +void Surf_SetupFrame(void) +{ + mleaf_t *leaf; + vec3_t temp; + + R_AnimateLight(); + r_framecount++; + + if (r_refdef.flags & Q2RDF_NOWORLDMODEL) + { + } +#ifdef Q2BSPS + else if (cl.worldmodel && (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)) + { + static mleaf_t fakeleaf; + mleaf_t *leaf; + + r_viewleaf = &fakeleaf; //so we can use quake1 rendering routines for q2 bsps. + r_viewleaf->contents = Q1CONTENTS_EMPTY; + r_viewleaf2 = NULL; + + r_oldviewcluster = r_viewcluster; + r_oldviewcluster2 = r_viewcluster2; + leaf = RMod_PointInLeaf (cl.worldmodel, r_origin); + r_viewcluster = r_viewcluster2 = leaf->cluster; + + // check above and below so crossing solid water doesn't draw wrong + if (!leaf->contents) + { // look down a bit + vec3_t temp; + + VectorCopy (r_origin, temp); + temp[2] -= 16; + leaf = RMod_PointInLeaf (cl.worldmodel, temp); + if ( !(leaf->contents & Q2CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2) ) + r_viewcluster2 = leaf->cluster; + } + else + { // look up a bit + vec3_t temp; + + VectorCopy (r_origin, temp); + temp[2] += 16; + leaf = RMod_PointInLeaf (cl.worldmodel, temp); + if ( !(leaf->contents & Q2CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2) ) + r_viewcluster2 = leaf->cluster; + } + } +#endif + else + { + r_oldviewleaf = r_viewleaf; + r_oldviewleaf2 = r_viewleaf2; + r_viewleaf = RMod_PointInLeaf (cl.worldmodel, r_origin); + + if (!r_viewleaf) + { + } + else if (r_viewleaf->contents == Q1CONTENTS_EMPTY) + { //look down a bit + VectorCopy (r_origin, temp); + temp[2] -= 16; + leaf = RMod_PointInLeaf (cl.worldmodel, temp); + if (leaf->contents <= Q1CONTENTS_WATER && leaf->contents >= Q1CONTENTS_LAVA) + r_viewleaf2 = leaf; + else + r_viewleaf2 = NULL; + } + else if (r_viewleaf->contents <= Q1CONTENTS_WATER && r_viewleaf->contents >= Q1CONTENTS_LAVA) + { //in water, look up a bit. + + VectorCopy (r_origin, temp); + temp[2] += 16; + leaf = RMod_PointInLeaf (cl.worldmodel, temp); + if (leaf->contents == Q1CONTENTS_EMPTY) + r_viewleaf2 = leaf; + else + r_viewleaf2 = NULL; + } + else + r_viewleaf2 = NULL; + + if (r_viewleaf) + V_SetContentsColor (r_viewleaf->contents); + } +} + +/* +============= +R_DrawWorld +============= +*/ + +void Surf_DrawWorld (void) +{ + qbyte *vis; + RSpeedLocals(); + entity_t ent; + + Surf_SetupFrame(); + + memset (&ent, 0, sizeof(ent)); + ent.model = cl.worldmodel; + currentmodel = cl.worldmodel; + + currententity = &ent; +#ifdef TERRAIN + if (currentmodel->type == mod_heightmap) + GL_DrawHeightmapModel(currententity); + else +#endif + { + Surf_ClearChains(); + + RSpeedRemark(); + +#ifdef Q2BSPS + if (ent.model->fromgame == fg_quake2 || ent.model->fromgame == fg_quake3) + { + int leafnum; + int clientarea; +#ifdef QUAKE2 + if (cls.protocol == CP_QUAKE2) //we can get server sent info + memcpy(areabits, cl.q2frame.areabits, sizeof(areabits)); + else +#endif + { //generate the info each frame. + leafnum = CM_PointLeafnum (cl.worldmodel, r_refdef.vieworg); + clientarea = CM_LeafArea (cl.worldmodel, leafnum); + CM_WriteAreaBits(cl.worldmodel, areabits, clientarea); + } +#ifdef Q3BSPS + if (ent.model->fromgame == fg_quake3) + { + vis = R_MarkLeaves_Q3 (); + Surf_LeafWorldNode (); + } + else +#endif + { + vis = R_MarkLeaves_Q2 (); + VectorCopy (r_refdef.vieworg, modelorg); + Surf_RecursiveQ2WorldNode (cl.worldmodel->nodes); + } + } + else +#endif + { + extern cvar_t temp1; + if (0)//temp1.value) + vis = R_MarkLeafSurfaces_Q1(); + else + { + vis = R_MarkLeaves_Q1 (); + VectorCopy (r_refdef.vieworg, modelorg); + Surf_RecursiveWorldNode (cl.worldmodel->nodes, 0xf); + } + } + + RSpeedEnd(RSPEED_WORLDNODE); + TRACE(("dbg: calling BE_DrawWorld\n")); + BE_DrawWorld(vis); + Surf_CleanChains(); + + + Surf_LessenStains(); + } +} + + + +/* +============================================================================= + + LIGHTMAP ALLOCATION + +============================================================================= +*/ + +// returns a texture number and the position inside it +static int Surf_LM_AllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + int texnum; + + for (texnum=0 ; ; texnum++) + { + if (texnum == numlightmaps) //allocate 4 more lightmap slots. not much memory usage, but we don't want any caps here. + { + lightmap = BZ_Realloc(lightmap, sizeof(*lightmap)*(numlightmaps+4)); + lightmap[numlightmaps+0] = NULL; + lightmap[numlightmaps+1] = NULL; + lightmap[numlightmaps+2] = NULL; + lightmap[numlightmaps+3] = NULL; + + lightmap_textures = BZ_Realloc(lightmap_textures, sizeof(*lightmap_textures)*(numlightmaps+4)); + lightmap_textures[numlightmaps+0] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + lightmap_textures[numlightmaps+1] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + lightmap_textures[numlightmaps+2] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + lightmap_textures[numlightmaps+3] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + + deluxmap_textures = BZ_Realloc(deluxmap_textures, sizeof(*deluxmap_textures)*(numlightmaps+4)); + deluxmap_textures[numlightmaps+0] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + deluxmap_textures[numlightmaps+1] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + deluxmap_textures[numlightmaps+2] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + deluxmap_textures[numlightmaps+3] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + numlightmaps+=4; + } + if (!lightmap[texnum]) + { + lightmap[texnum] = Z_Malloc(sizeof(*lightmap[texnum])); + lightmap[texnum]->meshchain = NULL; + lightmap[texnum]->modified = true; + // reset stainmap since it now starts at 255 + memset(lightmap[texnum]->stainmaps, 255, sizeof(lightmap[texnum]->stainmaps)); + + //clear out the deluxmaps incase there is none on the map. + for (j = 0; j < LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3; j+=3) + { + lightmap[texnum]->deluxmaps[j+0] = 128; + lightmap[texnum]->deluxmaps[j+1] = 128; + lightmap[texnum]->deluxmaps[j+2] = 255; + } + } + + + best = LMBLOCK_HEIGHT; + + for (i=0 ; iallocated[i+j] >= best) + break; + if (lightmap[texnum]->allocated[i+j] > best2) + best2 = lightmap[texnum]->allocated[i+j]; + } + if (j == w) + { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > LMBLOCK_HEIGHT) + continue; + + for (i=0 ; iallocated[*x + i] = best + h; + + return texnum; + } + + Sys_Error ("AllocBlock: full"); + return 0; +} + +//quake3 maps have their lightmaps in gl style already. +//rather than forgetting that and redoing it, let's just keep the data. +static int Surf_LM_FillBlock (int texnum, int w, int h, int x, int y) +{ + int i, l; + while (texnum >= numlightmaps) //allocate 4 more lightmap slots. not much memory usage, but we don't want any caps here. + { + lightmap = BZ_Realloc(lightmap, sizeof(*lightmap)*(numlightmaps+4)); + lightmap[numlightmaps+0] = NULL; + lightmap[numlightmaps+1] = NULL; + lightmap[numlightmaps+2] = NULL; + lightmap[numlightmaps+3] = NULL; + + lightmap_textures = BZ_Realloc(lightmap_textures, sizeof(*lightmap_textures)*(numlightmaps+4)); + lightmap_textures[numlightmaps+0] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + lightmap_textures[numlightmaps+1] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + lightmap_textures[numlightmaps+2] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + lightmap_textures[numlightmaps+3] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + + deluxmap_textures = BZ_Realloc(deluxmap_textures, sizeof(*deluxmap_textures)*(numlightmaps+4)); + deluxmap_textures[numlightmaps+0] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + deluxmap_textures[numlightmaps+1] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + deluxmap_textures[numlightmaps+2] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + deluxmap_textures[numlightmaps+3] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + numlightmaps+=4; + } + for (i = texnum; i >= 0; i--) + { + if (!lightmap[i]) + { + lightmap[i] = BZ_Malloc(sizeof(*lightmap[i])); + lightmap[i]->meshchain = NULL; + lightmap[i]->modified = true; + for (l=0 ; lallocated[l] = LMBLOCK_HEIGHT; + } + + //clear out the deluxmaps incase there is none on the map. + for (l = 0; l < LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3; l+=3) + { + lightmap[i]->deluxmaps[l+0] = 0; + lightmap[i]->deluxmaps[l+1] = 0; + lightmap[i]->deluxmaps[l+2] = 255; + } + + //maybe someone screwed with my lightmap... + memset(lightmap[i]->lightmaps, 255, LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3); + if (cl.worldmodel->lightdata) + { + memcpy(lightmap[i]->lightmaps, cl.worldmodel->lightdata+3*LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*i, LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3); + } + else + { + char basename[MAX_QPATH]; + COM_StripExtension(cl.worldmodel->name, basename, sizeof(basename)); + lightmap_textures[i] = R_LoadHiResTexture(va("%s/lm_%04i", basename, i), NULL, IF_NOALPHA|IF_NOGAMMA); + lightmap[i]->modified = false; + } + + } + else + break; + } + return texnum; +} + +static mvertex_t *r_pcurrentvertbase; + +static int nColinElim; + +/* +================ +BuildSurfaceDisplayList +================ +*/ +static void Surf_BuildSurfaceDisplayList (msurface_t *fa) +{ + int i, lindex, lnumverts; + medge_t *pedges, *r_pedge; + int vertpage; + float *vec; + float s, t; + int lm; + +// reconstruct the polygon + pedges = currentmodel->edges; + lnumverts = fa->numedges; + vertpage = 0; + + if (lnumverts<3) + return; //q3 flares. + + { //build a nice mesh instead of a poly. + int size = sizeof(mesh_t) + sizeof(index_t)*(lnumverts-2)*3 + (sizeof(vecV_t) + 3*sizeof(vec3_t) + 2*sizeof(vec2_t) + sizeof(vec4_t))*lnumverts; + mesh_t *mesh; + + fa->mesh = mesh = Hunk_Alloc(size); + mesh->xyz_array = (vecV_t*)(mesh + 1); + mesh->normals_array = (vec3_t*)(mesh->xyz_array + lnumverts); + mesh->snormals_array = (vec3_t*)(mesh->normals_array + lnumverts); + mesh->tnormals_array = (vec3_t*)(mesh->snormals_array + lnumverts); + mesh->st_array = (vec2_t*)(mesh->tnormals_array + lnumverts); + mesh->lmst_array = (vec2_t*)(mesh->st_array + lnumverts); + mesh->colors4f_array = (vec4_t*)(mesh->lmst_array + lnumverts); + mesh->indexes = (index_t*)(mesh->colors4f_array + lnumverts); + + mesh->numindexes = (lnumverts-2)*3; + mesh->numvertexes = lnumverts; + mesh->istrifan = true; + + for (i=0 ; iindexes[i*3] = 0; + mesh->indexes[i*3+1] = i+1; + mesh->indexes[i*3+2] = i+2; + } + + for (i=0 ; isurfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + vec = r_pcurrentvertbase[r_pedge->v[0]].position; + } + else + { + r_pedge = &pedges[-lindex]; + vec = r_pcurrentvertbase[r_pedge->v[1]].position; + } + + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + + VectorCopy (vec, mesh->xyz_array[i]); + mesh->st_array[i][0] = s/fa->texinfo->texture->width; + mesh->st_array[i][1] = t/fa->texinfo->texture->height; + + s -= fa->texturemins[0]; + lm = s*fa->light_t; + s += fa->light_s*16; + s += 8; + s /= LMBLOCK_WIDTH*16; + + t -= fa->texturemins[1]; + lm += t; + t += fa->light_t*16; + t += 8; + t /= LMBLOCK_HEIGHT*16; + + mesh->lmst_array[i][0] = s; + mesh->lmst_array[i][1] = t; + + if (fa->flags & SURF_PLANEBACK) + VectorNegate(fa->plane->normal, mesh->normals_array[i]); + else + VectorCopy(fa->plane->normal, mesh->normals_array[i]); + VectorNegate(fa->texinfo->vecs[0], mesh->snormals_array[i]); + VectorNegate(fa->texinfo->vecs[1], mesh->tnormals_array[i]); + VectorNormalize(mesh->snormals_array[i]); + VectorNormalize(mesh->tnormals_array[i]); + + mesh->colors4f_array[i][0] = 1; + mesh->colors4f_array[i][1] = 1; + mesh->colors4f_array[i][2] = 1; + mesh->colors4f_array[i][3] = 1; + } + } +} + +/* +======================== +GL_CreateSurfaceLightmap +======================== +*/ +static void Surf_CreateSurfaceLightmap (msurface_t *surf, int shift) +{ + int smax, tmax; + qbyte *base, *luxbase; stmap *stainbase; + + if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) + surf->lightmaptexturenum = -1; + if (surf->texinfo->flags & TEX_SPECIAL) + surf->lightmaptexturenum = -1; + if (surf->lightmaptexturenum<0) + return; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + if (smax > LMBLOCK_WIDTH || tmax > LMBLOCK_HEIGHT || smax < 0 || tmax < 0) + { //whoa, buggy. + surf->lightmaptexturenum = -1; + return; + } + + if (currentmodel->fromgame == fg_quake3) + Surf_LM_FillBlock(surf->lightmaptexturenum, smax, tmax, surf->light_s, surf->light_t); + else + surf->lightmaptexturenum = Surf_LM_AllocBlock (smax, tmax, &surf->light_s, &surf->light_t); + base = lightmap[surf->lightmaptexturenum]->lightmaps; + base += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * lightmap_bytes; + + luxbase = lightmap[surf->lightmaptexturenum]->deluxmaps; + luxbase += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * 3; + + stainbase = lightmap[surf->lightmaptexturenum]->stainmaps; + stainbase += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * 3; + + Surf_BuildLightMap (surf, base, luxbase, stainbase, shift); +} + + + +void Surf_DeInit(void) +{ + int i; + for (i = 0; i < numlightmaps; i++) + { + if (!lightmap[i]) + break; + BZ_Free(lightmap[i]); + lightmap[i] = NULL; + } + + if (lightmap_textures) + { + for (i = 0; i < numlightmaps; i++) + R_DestroyTexture(lightmap_textures[i]); + BZ_Free(lightmap_textures); + } + if (lightmap) + BZ_Free(lightmap); + + lightmap_textures=NULL; + lightmap=NULL; + numlightmaps=0; +} + +/* +================== +GL_BuildLightmaps + +Builds the lightmap texture +with all the surfaces from all brush models +================== +*/ +void Surf_BuildLightmaps (void) +{ + int i, j, t; + model_t *m; + int shift; + + r_framecount = 1; // no dlightcache + + for (i = 0; i < numlightmaps; i++) + { + if (!lightmap[i]) + break; + BZ_Free(lightmap[i]); + lightmap[i] = NULL; + } + + if (cl.worldmodel->fromgame == fg_doom) + return; //no lightmaps. + + if ((cl.worldmodel->engineflags & MDLF_RGBLIGHTING) || cl.worldmodel->deluxdata || r_loadlits.value) + lightmap_bytes = 3; + else + lightmap_bytes = 1; + + if (cl.worldmodel->fromgame == fg_quake3 && lightmap_bytes != 3 && lightmap_bytes != 4) + lightmap_bytes = 3; + + for (j=1 ; jname[0] == '*') + continue; + + r_pcurrentvertbase = m->vertexes; + currentmodel = m; + shift = Surf_LightmapShift(currentmodel); + + for (t = 0; t < m->numtextures; t++) + { + for (i=0 ; inumsurfaces ; i++) + {//extra texture loop so we get slightly less texture switches + if (m->surfaces[i].texinfo->texture == m->textures[t]) + { + Surf_CreateSurfaceLightmap (m->surfaces + i, shift); + P_EmitSkyEffectTris(m, &m->surfaces[i]); + if (m->surfaces[i].mesh) //there are some surfaces that have a display list already (the subdivided ones) + continue; + Surf_BuildSurfaceDisplayList (m->surfaces + i); + } + } + } + + BE_GenBrushModelVBO(m); + } + + BE_UploadAllLightmaps(); +} +#endif diff --git a/engine/client/render.h b/engine/client/render.h index 0e9b6204..99402ee9 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -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); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 5dcdbf23..59199ea5 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -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; diff --git a/engine/client/vid.h b/engine/client/vid.h index e2d72a55..b14efcb6 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -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 diff --git a/engine/common/com_phys_ode.c b/engine/common/com_phys_ode.c index 3895acee..0d6a3360 100644 --- a/engine/common/com_phys_ode.c +++ b/engine/common/com_phys_ode.c @@ -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 diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index b672c6cb..0e987941 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -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 diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 936ef5a5..aba166bc 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -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 diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index ce4149f2..5e3aa8ea 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -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 diff --git a/engine/common/world.h b/engine/common/world.h index 68b5ea87..b8938dbf 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -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; diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index f145d5ca..80fe9b56 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -3,7 +3,17 @@ #include "shader.h" #include -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 ; imodel) + 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 ; inumtextures ; 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 diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index b63fd337..dba14425 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -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); diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 8118f783..18880b45 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -29444,6 +29444,10 @@ RelativePath="..\client\r_2d.c" > + + @@ -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 diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 6fac5ff6..32732290 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -293,11 +293,6 @@ static const char PCFPASS_SHADER[] = "\ }"; -extern texid_t *lightmap_textures; -extern texid_t *deluxmap_textures; -extern int lightmap_bytes; // 1, 2, or 4 -extern lightmapinfo_t **lightmap; -extern int numlightmaps; extern cvar_t r_shadow_glsl_offsetmapping; #if 0//def _DEBUG @@ -661,6 +656,7 @@ qboolean R_MeshWillExceed(mesh_t *mesh) return false; } +#ifdef RTLIGHTS //called from gl_shadow void BE_SetupForShadowMap(void) { @@ -678,6 +674,7 @@ void BE_SetupForShadowMap(void) shaderstate.shaderbits |= SBITS_MISC_DEPTHWRITE; // qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); } +#endif static texid_t T_Gen_CurrentRender(void) { @@ -2024,6 +2021,7 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas GLSlang_UseProgram(0); } +#ifdef RTLIGHTS qboolean BE_LightCullModel(vec3_t org, model_t *model) { if (shaderstate.mode == BEM_LIGHT || shaderstate.mode == BEM_STENCIL) @@ -2052,15 +2050,16 @@ qboolean BE_LightCullModel(vec3_t org, model_t *model) } return false; } +#endif //Note: Be cautious about using BEM_LIGHT here. void BE_SelectMode(backendmode_t mode, unsigned int flags) { extern int gldepthfunc; +#ifdef RTLIGHTS if (mode != shaderstate.mode) { - qglDisable(GL_POLYGON_OFFSET_FILL); shaderstate.curpolyoffset.factor = 0; shaderstate.curpolyoffset.unit = 0; @@ -2142,11 +2141,12 @@ qglPolygonOffset(shaderstate.curpolyoffset.factor, shaderstate.curpolyoffset.uni } } } - +#endif shaderstate.mode = mode; shaderstate.flags = flags; } +#ifdef RTLIGHTS void BE_SelectDLight(dlight_t *dl, vec3_t colour) { shaderstate.lightradius = dl->radius; @@ -2154,6 +2154,7 @@ void BE_SelectDLight(dlight_t *dl, vec3_t colour) VectorCopy(colour, shaderstate.lightcolours); shaderstate.curshadowmap = dl->stexture; } +#endif static void DrawMeshChain(const mesh_t *meshlist) { @@ -2437,7 +2438,7 @@ static void DrawSurfaceChain(msurface_t *s, shader_t *shader, vbo_t *vbo) 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, + LMBLOCK_WIDTH, theRect->h, ((lightmap_bytes==3)?GL_RGB:GL_LUMINANCE), GL_UNSIGNED_BYTE, lightmap[i]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; @@ -2469,7 +2470,7 @@ static void DrawSurfaceChain(msurface_t *s, shader_t *shader, vbo_t *vbo) } -void BE_BaseTextureChain(msurface_t *first) +static void BE_BaseTextureChain(msurface_t *first) { texture_t *t, *tex; shader_t *shader; @@ -2529,29 +2530,21 @@ static void BaseBrushTextures(entity_t *ent) } } - shift = GLR_LightmapShift(model); + shift = Surf_LightmapShift(model); //update lightmaps. for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++) - R_RenderDynamicLightmaps (s, shift); + Surf_RenderDynamicLightmaps (s, shift); } for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++) { - /*if (s->texinfo->flags & (Q2TI_TRANS33 | Q2TI_TRANS66)) - { - s->ownerent = currententity; - s->nextalphasurface = r_alpha_surfaces; - r_alpha_surfaces = s; - continue; - } - else */if (chain && s->texinfo->texture != chain->texinfo->texture) //last surface or not the same as the next + if (chain && s->texinfo->texture != chain->texinfo->texture) //last surface or not the same as the next { BE_BaseTextureChain(chain); chain = NULL; } - // s->flags |= sflags; s->texturechain = chain; chain = s; } @@ -2562,6 +2555,7 @@ static void BaseBrushTextures(entity_t *ent) qglPopMatrix(); } +#ifdef RTLIGHTS void BE_BaseEntShadowDepth(void) { extern model_t *currentmodel; @@ -2591,6 +2585,7 @@ void BE_BaseEntShadowDepth(void) } } } +#endif void BE_BaseEntTextures(void) { @@ -2686,18 +2681,7 @@ void BE_SubmitMeshes (void) checkerror(); } -static void BE_CleanChains(void) -{ - int i; - model_t *model = cl.worldmodel; - - for (i=0 ; inumtextures ; i++) - { - model->textures[i]->texturechain = NULL; - } -} - -void PPL_DrawWorld (qbyte *vis) +void BE_DrawWorld (qbyte *vis) { extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_lightmaps; RSpeedLocals(); @@ -2736,2591 +2720,5 @@ void PPL_DrawWorld (qbyte *vis) checkerror(); BE_DrawPolys(false); - - BE_CleanChains(); } - - - - -#if 0 - - -#include "quakedef.h" -#include "glquake.h" -#include "shader.h" - - -#ifdef GLQUAKE - -#define MAX_TEXTURE_UNITS 8 - -typedef struct { - GLenum currenttextures[MAX_TEXTURE_UNITS]; - GLenum texenvmode[MAX_TEXTURE_UNITS]; - - int currenttmu; - - qboolean in2d; -} gl_state_t; -gl_state_t gl_state; - -void GL_SetShaderState2D(qboolean is2d) -{ - gl_state.in2d = is2d; -} - -extern int *lightmap_textures; -extern int *deluxmap_textures; -extern int gl_filter_max; - -void GL_SelectTexture (GLenum target) -{ - gl_state.currenttmu = target; - if (qglClientActiveTextureARB) - { - qglClientActiveTextureARB(target + mtexid0); - qglActiveTextureARB(target + mtexid0); - } - else - qglSelectTextureSGIS(target + mtexid0); -} - -void GL_CheckTMUIs0(void) -{ - if (gl_state.currenttmu != 0) - { - Con_Printf("TMU is not 0\n"); - GL_SelectTexture(0); - } -} - -void GL_MBind( int target, int texnum ) -{ - GL_SelectTexture(target); - - if ( gl_state.currenttextures[gl_state.currenttmu] == texnum ) - return; - - gl_state.currenttextures[gl_state.currenttmu] = texnum; - bindTexFunc (GL_TEXTURE_2D, texnum); -} - -void GL_Bind (int texnum) -{ - if (gl_state.currenttextures[gl_state.currenttmu] == texnum) - return; - - gl_state.currenttextures[gl_state.currenttmu] = texnum; - - bindTexFunc (GL_TEXTURE_2D, texnum); -} -void GL_BindType (int type, int texnum) -{ - if (gl_state.currenttextures[gl_state.currenttmu] == texnum) - return; - - gl_state.currenttextures[gl_state.currenttmu] = texnum; - bindTexFunc (type, texnum); -} - -void GL_TexEnv( GLenum mode ) -{ - if ( mode != gl_state.texenvmode[gl_state.currenttmu] ) - { - qglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode ); - gl_state.texenvmode[gl_state.currenttmu] = mode; - } -} - -//vid restarted. -void GL_FlushBackEnd(void) -{ - int i; - for (i = 0; i < MAX_TEXTURE_UNITS; i++) - { - gl_state.currenttextures[i] = -1; - gl_state.texenvmode[i] = -1; - } -} - -typedef vec3_t mat3_t[3]; - - - - -#ifndef Q3SHADERS - -qboolean varrayactive; -void R_IBrokeTheArrays(void) -{ -} - -void R_BackendInit(void) -{ -} - - - - - -#else - -/* -Copyright (C) 2002-2003 Victor Luchits - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ -#define MAX_ARRAY_VERTS 8192 -#define MAX_ARRAY_INDEXES 8192 -#define MAX_ARRAY_NEIGHBORS 8192 -#define MAX_ARRAY_TRIANGLES (8192/3) -#define M_TWO_PI (M_PI*2) - -cvar_t r_detailtextures = SCVAR("r_detailtextures", "1"); -cvar_t r_showtris = SCVAR("r_showtris", "1"); -cvar_t r_shownormals = SCVAR("r_shownormals", "1"); - -mat3_t axisDefault={{1, 0, 0}, - {0, 1, 0}, - {0, 0, 1}}; - -void Matrix3_Transpose (mat3_t in, mat3_t out) -{ - out[0][0] = in[0][0]; - out[1][1] = in[1][1]; - out[2][2] = in[2][2]; - - out[0][1] = in[1][0]; - out[0][2] = in[2][0]; - out[1][0] = in[0][1]; - out[1][2] = in[2][1]; - out[2][0] = in[0][2]; - out[2][1] = in[1][2]; -} -void Matrix3_Multiply_Vec3 (mat3_t a, vec3_t b, vec3_t product) -{ - product[0] = a[0][0]*b[0] + a[0][1]*b[1] + a[0][2]*b[2]; - product[1] = a[1][0]*b[0] + a[1][1]*b[1] + a[1][2]*b[2]; - product[2] = a[2][0]*b[0] + a[2][1]*b[1] + a[2][2]*b[2]; -} - -int Matrix3_Compare(mat3_t in, mat3_t out) -{ - return memcmp(in, out, sizeof(mat3_t)); -} -extern model_t *currentmodel; - -#define clamp(v,min,max) (v) = (((v)<(min))?(min):(((v)>(max))?(max):(v))) - -extern qbyte FloatToByte( float x ); - - -#define FTABLE_SIZE 1024 -#define FTABLE_CLAMP(x) (((int)((x)*FTABLE_SIZE) & (FTABLE_SIZE-1))) -#define FTABLE_EVALUATE(table,x) (table ? table[FTABLE_CLAMP(x)] : frand()*((x)-floor(x))) - -static float r_sintable[FTABLE_SIZE]; -static float r_triangletable[FTABLE_SIZE]; -static float r_squaretable[FTABLE_SIZE]; -static float r_sawtoothtable[FTABLE_SIZE]; -static float r_inversesawtoothtable[FTABLE_SIZE]; - -index_t *indexesArray; -int *neighborsArray; -vec3_t *trNormalsArray; - -vec2_t *coordsArray; -vec2_t *lightmapCoordsArray; - -vec3_t vertexArray[MAX_ARRAY_VERTS*2]; -vec3_t normalsArray[MAX_ARRAY_VERTS]; - -vec3_t tempVertexArray[MAX_ARRAY_VERTS]; -vec3_t tempNormalsArray[MAX_ARRAY_VERTS]; -index_t tempIndexesArray[MAX_ARRAY_INDEXES]; - -index_t inIndexesArray[MAX_ARRAY_INDEXES]; -int inNeighborsArray[MAX_ARRAY_NEIGHBORS]; -vec3_t inTrNormalsArray[MAX_ARRAY_TRIANGLES]; -vec2_t inCoordsArray[MAX_ARRAY_VERTS]; -vec2_t inLightmapCoordsArray[MAX_ARRAY_VERTS]; -byte_vec4_t inColorsArray[MAX_ARRAY_VERTS]; - -static vec2_t tUnitCoordsArray[MAX_TEXTURE_UNITS][MAX_ARRAY_VERTS]; -static byte_vec4_t colorArray[MAX_ARRAY_VERTS]; - -int numVerts, numIndexes, numColors; - -qboolean r_arrays_locked; -qboolean r_blocked; - -int r_features; - -static int r_lmtex; - -static int r_texNums[SHADER_PASS_MAX]; -static int r_numUnits; - -index_t *currentIndex; -int *currentTrNeighbor; -float *currentTrNormal; -float *currentVertex; -float *currentNormal; -float *currentCoords; -float *currentLightmapCoords; -qbyte *currentColor; - -static int r_identityLighting; -static float r_localShaderTime; - -unsigned int r_numverts; -unsigned int r_numtris; -unsigned int r_numflushes; -int r_backendStart; - -int r_dlighttexture; - - extern qbyte *host_basepal; - extern qboolean gammaworks; - extern qbyte gammatable[256]; - -void R_FetchTopColour(int *retred, int *retgreen, int *retblue) -{ - int i; - - if (currententity->scoreboard) - { - i = currententity->scoreboard->ttopcolor; - } - else - i = TOP_RANGE>>4; - if (i > 8) - { - i<<=4; - } - else - { - i<<=4; - i+=15; - } - i*=3; - *retred = host_basepal[i+0]; - *retgreen = host_basepal[i+1]; - *retblue = host_basepal[i+2]; - if (!gammaworks) - { - *retred = gammatable[*retred]; - *retgreen = gammatable[*retgreen]; - *retblue = gammatable[*retblue]; - } -} -void R_FetchBottomColour(int *retred, int *retgreen, int *retblue) -{ - int i; - - if (currententity->scoreboard) - { - i = currententity->scoreboard->tbottomcolor; - } - else - i = BOTTOM_RANGE>>4; - if (i > 8) - { - i<<=4; - } - else - { - i<<=4; - i+=15; - } - i*=3; - *retred = host_basepal[i+0]; - *retgreen = host_basepal[i+1]; - *retblue = host_basepal[i+2]; - if (!gammaworks) - { - *retred = gammatable[*retred]; - *retgreen = gammatable[*retgreen]; - *retblue = gammatable[*retblue]; - } -} - -#define FOG_TEXTURE_WIDTH 32 -#define FOG_TEXTURE_HEIGHT 32 -int r_fogtexture; -void GL_InitFogTexture (void) -{ - qbyte data[FOG_TEXTURE_WIDTH*FOG_TEXTURE_HEIGHT]; - int x, y; - float tw = 1.0f / ((float)FOG_TEXTURE_WIDTH - 1.0f); - float th = 1.0f / ((float)FOG_TEXTURE_HEIGHT - 1.0f); - float tx, ty, t; - - if (r_fogtexture) - return; - - // - // fog texture - // - for ( y = 0, ty = 0.0f; y < FOG_TEXTURE_HEIGHT; y++, ty += th ) - { - for ( x = 0, tx = 0.0f; x < FOG_TEXTURE_WIDTH; x++, tx += tw ) - { - t = (float)(sqrt( tx ) * 255.0); - data[x+y*FOG_TEXTURE_WIDTH] = (qbyte)(min( t, 255.0f )); - } - } - - r_fogtexture = GL_AllocNewTexture(); - GL_Bind(r_fogtexture); - qglTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, FOG_TEXTURE_WIDTH, FOG_TEXTURE_HEIGHT, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); - - qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); - qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - - qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -void R_InitDynamicLightTexture (void) -{ - int x, y; - int dx2, dy, d; - qbyte data[64*64*4]; - - // - // dynamic light texture - // - - for (x = 0; x < 64; x++) - { - dx2 = x - 32; - dx2 = dx2 * dx2 + 8; - - for (y = 0; y < 64; y++) - { - dy = y - 32; - d = (int)(65536.0f * ((1.0f / (dx2 + dy * dy + 32.0f)) - 0.0005) + 0.5f); - if ( d < 50 ) d = 0; else if ( d > 255 ) d = 255; - - data[(y*64 + x) * 4 + 0] = d; - data[(y*64 + x) * 4 + 1] = d; - data[(y*64 + x) * 4 + 2] = d; - data[(y*64 + x) * 4 + 3] = 255; - } - } - - r_dlighttexture = GL_LoadTexture32("", 64, 64, (unsigned int*)data, true, false); - - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); -} - -void R_ResetTexState (void) -{ - coordsArray = inCoordsArray; - lightmapCoordsArray = inLightmapCoordsArray; - - currentCoords = coordsArray[0]; - currentLightmapCoords = lightmapCoordsArray[0]; - - numColors = 0; - currentColor = inColorsArray[0]; -} - - -void R_PushIndexes ( index_t *indexes, int *neighbors, vec3_t *trnormals, int numindexes, int features ) -{ - int i; - int numTris; - - // this is a fast path for non-batched geometry, use carefully - // used on pics, sprites, .dpm, .md3 and .md2 models - if ( features & MF_NONBATCHED ) { - if ( numindexes > MAX_ARRAY_INDEXES ) { - numindexes = MAX_ARRAY_INDEXES; - } - - // simply change indexesArray to point at indexes - numIndexes = numindexes; - indexesArray = indexes; - currentIndex = indexesArray + numIndexes; - - if ( neighbors ) { - neighborsArray = neighbors; - currentTrNeighbor = neighborsArray + numIndexes; - } - - if ( trnormals && (features & MF_TRNORMALS) ) { - numTris = numIndexes / 3; - - trNormalsArray = trnormals; - currentTrNormal = trNormalsArray[0] + numTris; - } - } - else - { - // clamp - if ( numIndexes + numindexes > MAX_ARRAY_INDEXES ) { - numindexes = MAX_ARRAY_INDEXES - numIndexes; - } - - numTris = numindexes / 3; - numIndexes += numindexes; - - // the following code assumes that R_PushIndexes is fed with triangles... - for ( i=0; iindexes || !mesh->xyz_array ) - { - return; - } - - r_features = features; - - R_PushIndexes ( mesh->indexes, mesh->trneighbors, mesh->trnormals, mesh->numindexes, features ); - - numverts = mesh->numvertexes; - if ( numVerts + numverts > MAX_ARRAY_VERTS ) - { - numverts = MAX_ARRAY_VERTS - numVerts; - } - - memcpy ( currentVertex, mesh->xyz_array, numverts * sizeof(vec3_t) ); - currentVertex += numverts * 3; - - if ( mesh->normals_array && (features & MF_NORMALS) ) { - memcpy ( currentNormal, mesh->normals_array, numverts * sizeof(vec3_t) ); - currentNormal += numverts * 3; - } - - if ( mesh->st_array && (features & MF_STCOORDS) ) - { - if ( features & MF_NONBATCHED ) - { - coordsArray = mesh->st_array; - currentCoords = coordsArray[0]; - } - else - { - memcpy ( currentCoords, mesh->st_array, numverts * sizeof(vec2_t) ); - } - - currentCoords += numverts * 2; - } - - if ( mesh->lmst_array && (features & MF_LMCOORDS) ) - { - if ( features & MF_NONBATCHED ) - { - lightmapCoordsArray = mesh->lmst_array; - currentLightmapCoords = lightmapCoordsArray[0]; - } - else - { - memcpy ( currentLightmapCoords, mesh->lmst_array, numverts * sizeof(vec2_t) ); - } - - currentLightmapCoords += numverts * 2; - } - - if ( mesh->colors_array && (features & MF_COLORS) ) - { - memcpy ( currentColor, mesh->colors_array, numverts * sizeof(byte_vec4_t) ); - currentColor += numverts * 4; - } - - numVerts += numverts; - r_numverts += numverts; -} - - -qboolean R_MeshWillExceed(mesh_t *mesh) -{ - if (numVerts + mesh->numvertexes > MAX_ARRAY_VERTS) - return true; - if (numIndexes + mesh->numindexes > MAX_ARRAY_INDEXES) - return true; - return false; -} - -extern index_t r_quad_indexes[6];// = { 0, 1, 2, 0, 2, 3 }; - -void R_FinishMeshBuffer ( meshbuffer_t *mb ); - -static float frand(void) -{ - return (rand()&32767)* (1.0/32767); -} - -//static float crand(void) -//{ -// return (rand()&32767)* (2.0/32767) - 1; -//} - -/* -============== -R_BackendInit -============== -*/ -void R_IBrokeTheArrays(void); -void R_BackendInit (void) -{ - int i; - double t; - - numVerts = 0; - numIndexes = 0; - numColors = 0; - - indexesArray = inIndexesArray; - currentIndex = indexesArray; - neighborsArray = inNeighborsArray; - trNormalsArray = inTrNormalsArray; - coordsArray = inCoordsArray; - lightmapCoordsArray = inLightmapCoordsArray; - - currentTrNeighbor = neighborsArray; - currentTrNormal = trNormalsArray[0]; - - currentVertex = vertexArray[0]; - currentNormal = normalsArray[0]; - - currentCoords = coordsArray[0]; - currentLightmapCoords = lightmapCoordsArray[0]; - - currentColor = inColorsArray[0]; - - r_fogtexture = 0; - - r_arrays_locked = false; - r_blocked = false; - - R_IBrokeTheArrays(); - - //FIZME: FTE already has some stuff along these lines, surly... -// if ( !r_ignorehwgamma->value ) -// r_identityLighting = (int)(255.0f / pow(2, max(0, floor(r_overbrightbits->value)))); -// else - r_identityLighting = 255; - - for ( i = 0; i < FTABLE_SIZE; i++ ) { - t = (double)i / (double)FTABLE_SIZE; - - r_sintable[i] = sin ( t * M_TWO_PI ); - - if (t < 0.25) - r_triangletable[i] = t * 4.0; - else if (t < 0.75) - r_triangletable[i] = 2 - 4.0 * t; - else - r_triangletable[i] = (t - 0.75) * 4.0 - 1.0; - - if (t < 0.5) - r_squaretable[i] = 1.0f; - else - r_squaretable[i] = -1.0f; - - r_sawtoothtable[i] = t; - r_inversesawtoothtable[i] = 1.0 - t; - } - - R_InitDynamicLightTexture(); - GL_InitFogTexture(); -} - -qboolean varrayactive; -void R_IBrokeTheArrays(void) -{ - varrayactive = true; - qglVertexPointer( 3, GL_FLOAT, 0, vertexArray ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); - - qglEnableClientState( GL_VERTEX_ARRAY ); -} - -/* -============== -R_BackendShutdown -============== -*/ -void R_BackendShutdown (void) -{ -} - -/* -============== -R_FastSin -============== -*/ -float R_FastSin ( float t ) -{ - return r_sintable[FTABLE_CLAMP(t)]; -} - -/* -============== -R_TableForFunc -============== -*/ -static float *R_TableForFunc ( unsigned int func ) -{ - switch (func) - { - case SHADER_FUNC_SIN: - return r_sintable; - - case SHADER_FUNC_TRIANGLE: - return r_triangletable; - - case SHADER_FUNC_SQUARE: - return r_squaretable; - - case SHADER_FUNC_SAWTOOTH: - return r_sawtoothtable; - - case SHADER_FUNC_INVERSESAWTOOTH: - return r_inversesawtoothtable; - } - - // assume noise - return NULL; -} - -/* -============== -R_BackendStartFrame -============== -*/ -void R_BackendStartFrame (void) -{ - r_numverts = 0; - r_numtris = 0; - r_numflushes = 0; -// r_backendStart = Sys_Milliseconds(); -} - -/* -============== -R_BackendEndFrame -============== -*/ -void R_BackendEndFrame (void) -{ - if (r_speeds.ival) - { - Con_Printf( "%4i wpoly %4i leafs %4i verts %4i tris %4i flushes\n", - c_brush_polys, - 0/*c_world_leafs*/, - r_numverts, - r_numtris, - r_numflushes ); - } -// time_backend = Sys_Milliseconds() - r_backendStart; -// r_backendStart = 0; -} - -/* -============== -R_LockArrays -============== -*/ -void R_LockArrays ( int numverts ) -{ - if ( r_arrays_locked ) - return; - - if ( qglLockArraysEXT != 0 ) { - qglLockArraysEXT( 0, numverts ); - r_arrays_locked = true; - } -} - -/* -============== -R_UnlockArrays -============== -*/ -void R_UnlockArrays (void) -{ - if ( !r_arrays_locked ) - return; - - if ( qglUnlockArraysEXT != 0 ) { - qglUnlockArraysEXT(); - r_arrays_locked = false; - } -} - -/* -============== -R_DrawTriangleStrips - -This function looks for and sends tristrips. -Original code by Stephen C. Taylor (Aftershock 3D rendering engine) -============== -*/ -void R_DrawTriangleStrips (index_t *indexes, int numindexes) -{ - int toggle; - index_t a, b, c, *index; - - c = 0; - index = indexes; - while ( c < numindexes ) { - toggle = 1; - - qglBegin( GL_TRIANGLE_STRIP ); - - qglArrayElement( index[0] ); - qglArrayElement( b = index[1] ); - qglArrayElement( a = index[2] ); - - c += 3; - index += 3; - - while ( c < numindexes ) { - if ( a != index[0] || b != index[1] ) { - break; - } - - if ( toggle ) { - qglArrayElement( b = index[2] ); - } else { - qglArrayElement( a = index[2] ); - } - - c += 3; - index += 3; - toggle = !toggle; - } - - qglEnd(); - } -} - -/* -============== -R_ClearArrays -============== -*/ -void R_ClearArrays (void) -{ - numVerts = 0; - numIndexes = 0; - - indexesArray = inIndexesArray; - currentIndex = indexesArray; - neighborsArray = inNeighborsArray; - trNormalsArray = inTrNormalsArray; - - currentTrNeighbor = neighborsArray; - currentTrNormal = trNormalsArray[0]; - - currentVertex = vertexArray[0]; - currentNormal = normalsArray[0]; - - R_ResetTexState (); - - r_blocked = false; -} - -/* -============== -R_FlushArrays -============== -*/ -void R_FlushArrays (void) -{ - if (!numVerts || !numIndexes) - { - return; - } - - if (numColors > 1) - { - qglEnableClientState(GL_COLOR_ARRAY); - } - else if (numColors == 1) - { - qglColor4ubv(colorArray[0]); - } - - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - - if (!r_arrays_locked) - { - R_DrawTriangleStrips(indexesArray, numIndexes); - } - else - { - qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexesArray); - } - - r_numtris += numIndexes / 3; - - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - - if (numColors > 1) - { - qglDisableClientState(GL_COLOR_ARRAY); - } - - r_numflushes++; -} - -/* -============== -R_FlushArraysMtex -============== -*/ -void R_FlushArraysMtex (void) -{ - int i; - - if (!numVerts || !numIndexes) - { - return; - } - - if (numColors > 1) - { - qglEnableClientState(GL_COLOR_ARRAY); - } - else if (numColors == 1) - { - qglColor4ubv(colorArray[0]); - } - - GL_MBind( 0, r_texNums[0] ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY); - for (i = 1; i < r_numUnits; i++) - { - GL_MBind(i, r_texNums[i]); - qglEnable (GL_TEXTURE_2D ); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if (!r_arrays_locked) - { - R_DrawTriangleStrips (indexesArray, numIndexes); - } - else - { - qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexesArray); - } - - r_numtris += numIndexes / 3; - - for ( i = r_numUnits - 1; i >= 0; i-- ) - { - GL_SelectTexture (i); - - if (i) - { - qglDisable (GL_TEXTURE_2D); - } - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if (numColors > 1) - { - qglDisableClientState(GL_COLOR_ARRAY); - } - - r_numflushes++; -} - -/* -================ -R_DeformVertices -================ -*/ -void R_DeformVertices ( meshbuffer_t *mb ) -{ - int i, j, k, pw, ph, p; - float args[4], deflect; - float *quad[4], *table; - shader_t *shader; - deformv_t *deformv; - vec3_t tv, rot_centre; - - shader = mb->shader; - deformv = &shader->deforms[0]; - - for (i = 0; i < shader->numdeforms; i++, deformv++) - { - switch (deformv->type) - { - case DEFORMV_NONE: - break; - - case DEFORMV_WAVE: - args[0] = deformv->func.args[0]; - args[1] = deformv->func.args[1]; - args[3] = deformv->func.args[2] + deformv->func.args[3] * r_localShaderTime; - table = R_TableForFunc ( deformv->func.type ); - - for ( j = 0; j < numVerts; j++ ) - { - deflect = deformv->args[0] * (vertexArray[j][0]+vertexArray[j][1]+vertexArray[j][2]) + args[3]; - deflect = FTABLE_EVALUATE ( table, deflect ) * args[1] + args[0]; - - // Deflect vertex along its normal by wave amount - VectorMA ( vertexArray[j], deflect, normalsArray[j], vertexArray[j] ); - } - break; - - case DEFORMV_NORMAL: - args[0] = deformv->args[1] * r_localShaderTime; - - for ( j = 0; j < numVerts; j++ ) - { - args[1] = normalsArray[j][2] * args[0]; - - deflect = deformv->args[0] * R_FastSin ( args[1] ); - normalsArray[j][0] *= deflect; - deflect = deformv->args[0] * R_FastSin ( args[1] + 0.25 ); - normalsArray[j][1] *= deflect; - VectorNormalizeFast ( normalsArray[j] ); - } - break; - - case DEFORMV_MOVE: - table = R_TableForFunc ( deformv->func.type ); - deflect = deformv->func.args[2] + r_localShaderTime * deformv->func.args[3]; - deflect = FTABLE_EVALUATE (table, deflect) * deformv->func.args[1] + deformv->func.args[0]; - - for ( j = 0; j < numVerts; j++ ) - VectorMA ( vertexArray[j], deflect, deformv->args, vertexArray[j] ); - break; - - case DEFORMV_BULGE: - pw = mb->mesh->patchWidth; - ph = mb->mesh->patchHeight; - - args[0] = deformv->args[0] / (float)ph; - args[1] = deformv->args[1]; - args[2] = r_localShaderTime / (deformv->args[2]*pw); - - for ( k = 0, p = 0; k < ph; k++ ) - { - deflect = R_FastSin ( (float)k * args[0] + args[2] ) * args[1]; - - for ( j = 0; j < pw; j++, p++ ) - VectorMA ( vertexArray[p], deflect, normalsArray[p], vertexArray[p] ); - } - break; - - case DEFORMV_AUTOSPRITE: - if ( numIndexes < 6 ) - break; - - for ( k = 0; k < numIndexes; k += 6 ) - { - mat3_t m0, m1, result; - - quad[0] = (float *)(vertexArray + indexesArray[k+0]); - quad[1] = (float *)(vertexArray + indexesArray[k+1]); - quad[2] = (float *)(vertexArray + indexesArray[k+2]); - - for ( j = 2; j >= 0; j-- ) - { - quad[3] = (float *)(vertexArray + indexesArray[k+3+j]); - if ( !VectorEquals (quad[3], quad[0]) && - !VectorEquals (quad[3], quad[1]) && - !VectorEquals (quad[3], quad[2]) ) { - break; - } - } - - VectorSubtract ( quad[0], quad[1], m0[0] ); - VectorSubtract ( quad[2], quad[1], m0[1] ); - CrossProduct ( m0[0], m0[1], m0[2] ); - VectorNormalizeFast ( m0[2] ); - VectorVectors ( m0[2], m0[1], m0[0] ); - - VectorCopy ( (&r_view_matrix[0]), m1[0] ); - VectorCopy ( (&r_view_matrix[4]), m1[1] ); - VectorCopy ( (&r_view_matrix[8]), m1[2] ); - - Matrix3_Multiply ( m1, m0, result ); - - for ( j = 0; j < 3; j++ ) - rot_centre[j] = (quad[0][j] + quad[1][j] + quad[2][j] + quad[3][j]) * 0.25 + currententity->origin[j]; - - for ( j = 0; j < 4; j++ ) - { - VectorSubtract ( quad[j], rot_centre, tv ); - Matrix3_Multiply_Vec3 ( result, tv, quad[j] ); - VectorAdd ( rot_centre, quad[j], quad[j] ); - } - } - break; - - case DEFORMV_AUTOSPRITE2: - if ( numIndexes < 6 ) - break; - - for ( k = 0; k < numIndexes; k += 6 ) - { - int long_axis, short_axis; - vec3_t axis; - float len[3]; - mat3_t m0, m1, m2, result; - - quad[0] = (float *)(vertexArray + indexesArray[k+0]); - quad[1] = (float *)(vertexArray + indexesArray[k+1]); - quad[2] = (float *)(vertexArray + indexesArray[k+2]); - - for ( j = 2; j >= 0; j-- ) - { - quad[3] = (float *)(vertexArray + indexesArray[k+3+j]); - if ( !VectorEquals (quad[3], quad[0]) && - !VectorEquals (quad[3], quad[1]) && - !VectorEquals (quad[3], quad[2]) ) - { - break; - } - } - - // build a matrix were the longest axis of the billboard is the Y-Axis - VectorSubtract ( quad[1], quad[0], m0[0] ); - VectorSubtract ( quad[2], quad[0], m0[1] ); - VectorSubtract ( quad[2], quad[1], m0[2] ); - len[0] = DotProduct ( m0[0], m0[0] ); - len[1] = DotProduct ( m0[1], m0[1] ); - len[2] = DotProduct ( m0[2], m0[2] ); - - if ( (len[2] > len[1]) && (len[2] > len[0]) ) - { - if ( len[1] > len[0] ) - { - long_axis = 1; - short_axis = 0; - } - else - { - long_axis = 0; - short_axis = 1; - } - } - else if ( (len[1] > len[2]) && (len[1] > len[0]) ) - { - if ( len[2] > len[0] ) - { - long_axis = 2; - short_axis = 0; - } - else - { - long_axis = 0; - short_axis = 2; - } - } - else //if ( (len[0] > len[1]) && (len[0] > len[2]) ) - { - if ( len[2] > len[1] ) - { - long_axis = 2; - short_axis = 1; - } - else - { - long_axis = 1; - short_axis = 2; - } - } - - if ( DotProduct (m0[long_axis], m0[short_axis]) ) - { - VectorNormalize2 ( m0[long_axis], axis ); - VectorCopy ( axis, m0[1] ); - - if ( axis[0] || axis[1] ) - { - VectorVectors ( m0[1], m0[2], m0[0] ); - } - else - { - VectorVectors ( m0[1], m0[0], m0[2] ); - } - } - else - { - VectorNormalize2 ( m0[long_axis], axis ); - VectorNormalize2 ( m0[short_axis], m0[0] ); - VectorCopy ( axis, m0[1] ); - CrossProduct ( m0[0], m0[1], m0[2] ); - } - - for ( j = 0; j < 3; j++ ) - rot_centre[j] = (quad[0][j] + quad[1][j] + quad[2][j] + quad[3][j]) * 0.25; - - if ( currententity ) - { - VectorAdd ( currententity->origin, rot_centre, tv ); - } - else - { - VectorCopy ( rot_centre, tv ); - } - VectorSubtract ( r_origin, tv, tv ); - - // filter any longest-axis-parts off the camera-direction - deflect = -DotProduct ( tv, axis ); - - VectorMA ( tv, deflect, axis, m1[2] ); - VectorNormalizeFast ( m1[2] ); - VectorCopy ( axis, m1[1] ); - CrossProduct ( m1[1], m1[2], m1[0] ); - - Matrix3_Transpose ( m1, m2 ); - Matrix3_Multiply ( m2, m0, result ); - - for ( j = 0; j < 4; j++ ) - { - VectorSubtract ( quad[j], rot_centre, tv ); - Matrix3_Multiply_Vec3 ( result, tv, quad[j] ); - VectorAdd ( rot_centre, quad[j], quad[j] ); - } - } - break; - - case DEFORMV_PROJECTION_SHADOW: - break; - - default: - break; - } - } -} - -void RB_CalcEnvironmentTexCoords( float *st ) -{ - int i; - float *v, *normal; - vec3_t viewer, reflected; - float d; - - vec3_t rorg; - - v = vertexArray[0]; - normal = normalsArray[0]; - - RotateLightVector(currententity->axis, currententity->origin, r_origin, rorg); - - for (i = 0 ; i < numVerts ; i++, v += 3, normal += 3, st += 2 ) - { - VectorSubtract (rorg, v, viewer); - VectorNormalizeFast (viewer); - - d = DotProduct (normal, viewer); - - reflected[0] = normal[0]*2*d - viewer[0]; - reflected[1] = normal[1]*2*d - viewer[1]; - reflected[2] = normal[2]*2*d - viewer[2]; - - st[0] = 0.5 + reflected[1] * 0.5; - st[1] = 0.5 - reflected[2] * 0.5; - } -} - -/* -============== -R_VertexTCBase -============== -*/ -float *R_VertexTCBase ( int tcgen, int unit ) -{ - int i; -// vec3_t t, n; - float *outCoords; -// vec3_t transform; -// mat3_t inverse_axis; -// mat3_t axis; - - outCoords = tUnitCoordsArray[unit][0]; - - if ( tcgen == TC_GEN_BASE ) - { - memcpy ( outCoords, coordsArray[0], sizeof(float) * 2 * numVerts ); - } - else if ( tcgen == TC_GEN_LIGHTMAP ) - { - memcpy ( outCoords, lightmapCoordsArray[0], sizeof(float) * 2 * numVerts ); - } - else if ( tcgen == TC_GEN_ENVIRONMENT ) - { - RB_CalcEnvironmentTexCoords(outCoords); //use genuine q3 code, to get it totally identical (for cell shading effects) - //plus, it looks like less overhead too - //I guess it depends on the size of the mesh - } - else if ( tcgen == TC_GEN_VECTOR ) - { - for ( i = 0; i < numVerts; i++, outCoords += 2 ) - { - static vec3_t tc_gen_s = { 1.0f, 0.0f, 0.0f }; - static vec3_t tc_gen_t = { 0.0f, 1.0f, 0.0f }; - - outCoords[0] = DotProduct ( tc_gen_s, vertexArray[i] ); - outCoords[1] = DotProduct ( tc_gen_t, vertexArray[i] ); - } - } - - return tUnitCoordsArray[unit][0]; -} - -/* -============== -R_ShaderpassTex -============== -*/ -int R_ShaderpassTex ( shaderpass_t *pass ) -{ - if (pass->flags & (SHADER_PASS_ANIMMAP|SHADER_PASS_LIGHTMAP|SHADER_PASS_VIDEOMAP|SHADER_PASS_DELUXMAP)) - { - if (pass->flags & SHADER_PASS_ANIMMAP) - { - return pass->anim_frames[(int)(pass->anim_fps * r_localShaderTime) % pass->anim_numframes]; - } - else if ((pass->flags & SHADER_PASS_LIGHTMAP) && r_lmtex >= 0) - { - return lightmap_textures[r_lmtex]; - } - else if ((pass->flags & SHADER_PASS_DELUXMAP) && r_lmtex >= 0) - { - return lightmap_textures[r_lmtex+1]; - } - else if ((pass->flags & SHADER_PASS_VIDEOMAP)) - { - return Media_UpdateForShader(pass->anim_frames[0], pass->cin); - } - } - - return pass->anim_frames[0] ? pass->anim_frames[0] : 0; -} - -/* -================ -R_ModifyTextureCoords -================ -*/ -void R_ModifyTextureCoords ( shaderpass_t *pass, int unit ) -{ - int i, j; - float *table; - float t1, t2, sint, cost; - float *tcArray, *buffer; - tcmod_t *tcmod; - - r_texNums[unit] = R_ShaderpassTex(pass); - - // we're smart enough not to copy data and simply switch the pointer - if (!pass->numtcmods) - { - if (pass->tcgen == TC_GEN_BASE) - { - qglTexCoordPointer(2, GL_FLOAT, 0, coordsArray); - } - else if (pass->tcgen == TC_GEN_LIGHTMAP) - { - qglTexCoordPointer(2, GL_FLOAT, 0, lightmapCoordsArray); - } - else if (pass->tcgen == TC_GEN_NORMAL) - { - qglTexCoordPointer(3, GL_FLOAT, 0, normalsArray); - } - else - { - qglTexCoordPointer(2, GL_FLOAT, 0, R_VertexTCBase(pass->tcgen, unit)); - } - return; - } - - buffer = R_VertexTCBase (pass->tcgen, unit); - qglTexCoordPointer(2, GL_FLOAT, 0, buffer); - - for (i = 0, tcmod = pass->tcmods; i < pass->numtcmods; i++, tcmod++) - { - tcArray = buffer; - - switch (tcmod->type) - { - case SHADER_TCMOD_ROTATE: - cost = tcmod->args[0] * r_localShaderTime; - sint = R_FastSin(cost); - cost = R_FastSin(cost + 0.25); - - for (j = 0; j < numVerts; j++, tcArray += 2) - { - t1 = cost * (tcArray[0] - 0.5f) - sint * (tcArray[1] - 0.5f) + 0.5f; - t2 = cost * (tcArray[1] - 0.5f) + sint * (tcArray[0] - 0.5f) + 0.5f; - tcArray[0] = t1; - tcArray[1] = t2; - } - break; - - case SHADER_TCMOD_SCALE: - t1 = tcmod->args[0]; - t2 = tcmod->args[1]; - - for (j = 0; j < numVerts; j++, tcArray += 2) - { - tcArray[0] = tcArray[0] * t1; - tcArray[1] = tcArray[1] * t2; - } - break; - - case SHADER_TCMOD_TURB: - t1 = tcmod->args[2] + r_localShaderTime * tcmod->args[3]; - t2 = tcmod->args[1]; - - for (j = 0; j < numVerts; j++, tcArray += 2) - { - tcArray[0] = tcArray[0] + R_FastSin (tcArray[0]*t2+t1) * t2; - tcArray[1] = tcArray[1] + R_FastSin (tcArray[1]*t2+t1) * t2; - } - break; - - case SHADER_TCMOD_STRETCH: - table = R_TableForFunc(tcmod->args[0]); - t2 = tcmod->args[3] + r_localShaderTime * tcmod->args[4]; - t1 = FTABLE_EVALUATE(table, t2) * tcmod->args[2] + tcmod->args[1]; - t1 = t1 ? 1.0f / t1 : 1.0f; - t2 = 0.5f - 0.5f * t1; - - for (j = 0; j < numVerts; j++, tcArray += 2) - { - tcArray[0] = tcArray[0] * t1 + t2; - tcArray[1] = tcArray[1] * t1 + t2; - } - break; - - case SHADER_TCMOD_SCROLL: - t1 = tcmod->args[0] * r_localShaderTime; - t2 = tcmod->args[1] * r_localShaderTime; - - for (j = 0; j < numVerts; j++, tcArray += 2) - { - tcArray[0] = tcArray[0] + t1; - tcArray[1] = tcArray[1] + t2; - } - break; - - case SHADER_TCMOD_TRANSFORM: - for (j = 0; j < numVerts; j++, tcArray += 2) - { - t1 = tcArray[0]; - t2 = tcArray[1]; - tcArray[0] = t1 * tcmod->args[0] + t2 * tcmod->args[2] + tcmod->args[4]; - tcArray[1] = t2 * tcmod->args[1] + t1 * tcmod->args[3] + tcmod->args[5]; - } - break; - - default: - break; - } - } -} - - -#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist) -#define VectorScalef(a, b, c) c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b - -/* -================ -R_ModifyColor -================ -*/ -void R_ModifyColor ( meshbuffer_t *mb, shaderpass_t *pass ) -{ - - int i, b; - float *table, c, a; - vec3_t t, v; - shader_t *shader; - qbyte *bArray, *vArray; - qboolean fogged, noArray; - shaderfunc_t *rgbgenfunc, *alphagenfunc; - - shader = mb->shader; - fogged = mb->fog && (shader->sort >= SHADER_SORT_UNDERWATER) && - !(pass->flags & SHADER_PASS_DEPTHWRITE) && !shader->fog_dist; - noArray = (pass->flags & SHADER_PASS_NOCOLORARRAY) && !fogged; - rgbgenfunc = &pass->rgbgen_func; - alphagenfunc = &pass->alphagen_func; - - if (noArray) - { - numColors = 1; - } - else - { - numColors = numVerts; - } - - bArray = colorArray[0]; - vArray = inColorsArray[0]; - - switch (pass->rgbgen) - { - default: - case RGB_GEN_IDENTITY: - memset ( bArray, 255, sizeof(byte_vec4_t)*numColors ); - break; - - case RGB_GEN_IDENTITY_LIGHTING: - memset ( bArray, r_identityLighting, sizeof(byte_vec4_t)*numColors ); - break; - - case RGB_GEN_CONST: - for ( i = 0; i < numColors; i++, bArray += 4 ) { - bArray[0] = FloatToByte (rgbgenfunc->args[0]); - bArray[1] = FloatToByte (rgbgenfunc->args[1]); - bArray[2] = FloatToByte (rgbgenfunc->args[2]); - } - break; - - case RGB_GEN_WAVE: - table = R_TableForFunc(rgbgenfunc->type); - c = rgbgenfunc->args[2] + r_localShaderTime * rgbgenfunc->args[3]; - c = FTABLE_EVALUATE(table, c) * rgbgenfunc->args[1] + rgbgenfunc->args[0]; - clamp(c, 0.0f, 1.0f); - - memset ( bArray, FloatToByte (c), sizeof(byte_vec4_t)*numColors ); - break; - - case RGB_GEN_ENTITY: - ((qbyte*)&b)[0] = currententity->shaderRGBAf[0]; - ((qbyte*)&b)[1] = currententity->shaderRGBAf[1]; - ((qbyte*)&b)[2] = currententity->shaderRGBAf[2]; - ((qbyte*)&b)[3] = currententity->shaderRGBAf[3]; - for (i = 0; i < numColors; i++, bArray += 4) - { - *(int *)bArray = b; - } - break; - - case RGB_GEN_ONE_MINUS_ENTITY: - ((qbyte*)&b)[0] = 255-currententity->shaderRGBAf[0]; - ((qbyte*)&b)[1] = 255-currententity->shaderRGBAf[1]; - ((qbyte*)&b)[2] = 255-currententity->shaderRGBAf[2]; - ((qbyte*)&b)[3] = 255-currententity->shaderRGBAf[3]; - for (i = 0; i < numColors; i++, bArray += 4) - { - *(int *)bArray = b; - } - break; - - case RGB_GEN_VERTEX: - case RGB_GEN_EXACT_VERTEX: - memcpy (bArray, vArray, sizeof(byte_vec4_t)*numColors); - break; - - case RGB_GEN_TOPCOLOR: //multiply vertex by topcolor (for player models) - { - int rc, gc, bc; - R_FetchTopColour(&rc, &gc, &bc); - - R_LightArrays((byte_vec4_t*)vArray, numColors, normalsArray); - - for (i = 0; i < numColors; i++, bArray += 4, vArray += 4) - { - bArray[0] = (vArray[0]*rc)>>8; - bArray[1] = (vArray[1]*gc)>>8; - bArray[2] = (vArray[2]*bc)>>8; - } - break; - } - - case RGB_GEN_BOTTOMCOLOR: //multiply vertex by bottomcolor (for player models) - { - int rc, gc, bc; - R_FetchBottomColour(&rc, &gc, &bc); - - R_LightArrays((byte_vec4_t*)vArray, numColors, normalsArray); - - for (i = 0; i < numColors; i++, bArray += 4, vArray += 4) - { - bArray[0] = (vArray[0]*rc)>>8; - bArray[1] = (vArray[1]*gc)>>8; - bArray[2] = (vArray[2]*bc)>>8; - } - break; - } - - - case RGB_GEN_ONE_MINUS_VERTEX: - for (i = 0; i < numColors; i++, bArray += 4, vArray += 4) - { - bArray[0] = 255 - vArray[0]; - bArray[1] = 255 - vArray[1]; - bArray[2] = 255 - vArray[2]; - } - break; - - case RGB_GEN_LIGHTING_DIFFUSE: - if (!currententity) - { - memset (bArray, 255, sizeof(byte_vec4_t)*numColors); - } - else - { - R_LightArrays((byte_vec4_t*)bArray, numColors, normalsArray); - } - break; - } - - bArray = colorArray[0]; - vArray = inColorsArray[0]; - - switch (pass->alphagen) - { - default: - case ALPHA_GEN_IDENTITY: - for (i = 0; i < numColors; i++, bArray += 4) - { - bArray[3] = 255; - } - break; - - case ALPHA_GEN_CONST: - b = FloatToByte ( alphagenfunc->args[0] ); - - for (i = 0; i < numColors; i++, bArray += 4) - { - bArray[3] = b; - } - break; - - case ALPHA_GEN_WAVE: - table = R_TableForFunc ( alphagenfunc->type ); - a = alphagenfunc->args[2] + r_localShaderTime * alphagenfunc->args[3]; - a = FTABLE_EVALUATE ( table, a ) * alphagenfunc->args[1] + alphagenfunc->args[0]; - b = FloatToByte ( bound (0.0f, a, 1.0f) ); - - for (i = 0; i < numColors; i++, bArray += 4) - { - bArray[3] = b; - } - break; - - case ALPHA_GEN_PORTAL: - VectorAdd(vertexArray[0], currententity->origin, v); - VectorSubtract(r_origin, v, t); - a = VectorLength ( t ) * (1.0 / 255.0); - clamp ( a, 0.0f, 1.0f ); - b = FloatToByte ( a ); - - for (i = 0; i < numColors; i++, bArray += 4) - { - bArray[3] = b; - } - break; - - case ALPHA_GEN_VERTEX: - for (i = 0; i < numColors; i++, bArray += 4, vArray += 4) - { - bArray[3] = vArray[3]; - } - break; - - case ALPHA_GEN_ENTITY: - if (pass->rgbgen != RGB_GEN_ENTITY) - {//rgbgenentity copies across ints rather than chars. it comes padded with the alpha too. - unsigned char value = bound(0, currententity->shaderRGBAf[3]*255, 255); - for ( i = 0; i < numColors; i++, bArray += 4 ) - { - bArray[3] = value; - } - } - break; - - - case ALPHA_GEN_SPECULAR: - { - mat3_t axis; - AngleVectors(currententity->angles, axis[0], axis[1], axis[2]); - VectorSubtract(r_origin, currententity->origin, t); - - if (!Matrix3_Compare(axis, axisDefault)) - { - Matrix3_Multiply_Vec3(axis, t, v ); - } - else - { - VectorCopy(t, v); - } - - for (i = 0; i < numColors; i++, bArray += 4) - { - VectorSubtract(v, vertexArray[i], t); - a = DotProduct(t, normalsArray[i] ) * Q_rsqrt(DotProduct(t,t)); - a = a * a * a * a * a; - bArray[3] = FloatToByte(bound (0.0f, a, 1.0f)); - } - } - break; - - } - - - if ( fogged ) - { - float dist, vdist; - mplane_t *fogplane; - vec3_t diff, viewtofog, fog_vpn; - - fogplane = mb->fog->visibleplane; - if (!fogplane) - return; - dist = PlaneDiff ( r_origin, fogplane ); - - if ( shader->flags & SHADER_SKY ) - { - if ( dist > 0 ) - VectorScale( fogplane->normal, -dist, viewtofog ); - else - VectorClear( viewtofog ); - } - else - { - VectorCopy ( currententity->origin, viewtofog ); - } - - VectorScalef ( vpn, mb->fog->shader->fog_dist, fog_vpn ); - - bArray = colorArray[0]; - for ( i = 0; i < numColors; i++, bArray += 4 ) - { - VectorAdd ( vertexArray[i], viewtofog, diff ); - - // camera is inside the fog - if ( dist < 0 ) { - VectorSubtract ( diff, r_origin, diff ); - - c = DotProduct ( diff, fog_vpn ); - a = (1.0f - bound ( 0, c, 1.0f )) * (1.0 / 255.0); - } - else - { - vdist = PlaneDiff ( diff, fogplane ); - - if ( vdist < 0 ) - { - VectorSubtract ( diff, r_origin, diff ); - - c = vdist / ( vdist - dist ); - c *= DotProduct ( diff, fog_vpn ); - a = (1.0f - bound ( 0, c, 1.0f )) * (1.0 / 255.0); - } - else - { - a = 1.0 / 255.0; - } - } - - if (pass->blendmode == GL_ADD || - ((pass->blendsrc == GL_ZERO) && (pass->blenddst == GL_ONE_MINUS_SRC_COLOR)) ) { - bArray[0] = FloatToByte ( (float)bArray[0]*a ); - bArray[1] = FloatToByte ( (float)bArray[1]*a ); - bArray[2] = FloatToByte ( (float)bArray[2]*a ); - } - else - { - bArray[3] = FloatToByte ( (float)bArray[3]*a ); - } - } - } -} - -/* -================ -R_SetShaderState -================ -*/ -void R_SetShaderState ( shader_t *shader ) -{ -// Face culling - if ( !gl_cull.value || (r_features & MF_NOCULL) ) - { - qglDisable ( GL_CULL_FACE ); - } - else - { - if ( shader->flags & SHADER_CULL_FRONT ) - { - qglEnable ( GL_CULL_FACE ); - qglCullFace ( GL_FRONT ); - } - else if ( shader->flags & SHADER_CULL_BACK ) - { - qglEnable ( GL_CULL_FACE ); - qglCullFace ( GL_BACK ); - } - else - { - qglDisable ( GL_CULL_FACE ); - } - } - - if ( shader->flags & SHADER_POLYGONOFFSET ) - { - qglEnable ( GL_POLYGON_OFFSET_FILL ); - } - else - { - qglDisable ( GL_POLYGON_OFFSET_FILL ); - } -} - -/* -================ -R_SetShaderpassState -================ -*/ -void R_SetShaderpassState ( shaderpass_t *pass, qboolean mtex ) -{ - if ( (mtex && (pass->blendmode != GL_REPLACE)) || (pass->flags & SHADER_PASS_BLEND) ) - { - qglEnable ( GL_BLEND ); - qglBlendFunc ( pass->blendsrc, pass->blenddst ); - } - else - { - qglDisable ( GL_BLEND ); - } - - if ( pass->flags & SHADER_PASS_ALPHAFUNC ) - { - qglEnable ( GL_ALPHA_TEST ); - - if ( pass->alphafunc == SHADER_ALPHA_GT0 ) - { - qglAlphaFunc ( GL_GREATER, 0 ); - } - else if ( pass->alphafunc == SHADER_ALPHA_LT128 ) - { - qglAlphaFunc ( GL_LESS, 0.5f ); - } - else if ( pass->alphafunc == SHADER_ALPHA_GE128 ) - { - qglAlphaFunc ( GL_GEQUAL, 0.5f ); - } - } - else - { - qglDisable ( GL_ALPHA_TEST ); - } - - // nasty hack!!! - if ( !gl_state.in2d ) - { - extern int gldepthfunc; - if (gldepthfunc == GL_LEQUAL) - qglDepthFunc ( pass->depthfunc ); - else - { - switch(pass->depthfunc) - { - case GL_LESS: - qglDepthFunc ( GL_GREATER ); - break; - case GL_LEQUAL: - qglDepthFunc ( GL_GEQUAL ); - break; - case GL_GREATER: - qglDepthFunc ( GL_LESS ); - break; - case GL_GEQUAL: - qglDepthFunc ( GL_LEQUAL ); - break; - - case GL_NEVER: - case GL_EQUAL: - case GL_ALWAYS: - case GL_NOTEQUAL: - default: - qglDepthFunc ( pass->depthfunc ); - } - } - - if ( pass->flags & SHADER_PASS_DEPTHWRITE ) - { - qglDepthMask ( GL_TRUE ); - } - else - { - qglDepthMask ( GL_FALSE ); - } - } - else - { - qglDepthFunc ( GL_ALWAYS ); - qglDepthMask ( GL_FALSE ); - } -} - -/* -================ -R_RenderMeshGeneric -================ -*/ -void R_RenderMeshGeneric ( meshbuffer_t *mb, shaderpass_t *pass ) -{ - R_SetShaderpassState ( pass, false ); - R_ModifyTextureCoords ( pass, 0 ); - R_ModifyColor ( mb, pass ); - - if ( pass->blendmode == GL_REPLACE ) - GL_TexEnv( GL_REPLACE ); - else - GL_TexEnv ( GL_MODULATE ); - GL_Bind ( r_texNums[0] ); - - R_FlushArrays (); -} - -/* -================ -R_RenderMeshMultitextured -================ -*/ - -void R_RenderMeshMultitextured ( meshbuffer_t *mb, shaderpass_t *pass ) -{ - int i; - - r_numUnits = pass->numMergedPasses; - - GL_SelectTexture( 0 ); - GL_TexEnv( pass->blendmode ); - R_SetShaderpassState ( pass, true ); - R_ModifyTextureCoords ( pass, 0 ); - R_ModifyColor ( mb, pass ); - - for ( i = 1, pass++; i < r_numUnits; i++, pass++ ) - { - GL_SelectTexture( i ); - GL_TexEnv( pass->blendmode ); - R_ModifyTextureCoords ( pass, i ); - } - - R_FlushArraysMtex (); -} - -/* -================ -R_RenderMeshCombined -================ -*/ -void R_RenderMeshCombined ( meshbuffer_t *mb, shaderpass_t *pass ) -{ - int i; - - r_numUnits = pass->numMergedPasses; - - R_SetShaderpassState ( pass, true ); - R_ModifyColor ( mb, pass ); - - GL_SelectTexture( 0 ); - if ( pass->blendmode == GL_REPLACE ) - GL_TexEnv( GL_REPLACE ); - else - GL_TexEnv( GL_MODULATE ); - R_ModifyTextureCoords ( pass, 0 ); - - for ( i = 1, pass++; i < r_numUnits; i++, pass++ ) - { - GL_SelectTexture( i ); - - - switch ( pass->blendmode ) - { - case GL_DOT3_RGB_ARB: - GL_TexEnv (GL_COMBINE_EXT); - qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); - qglTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, pass->blendmode); - break; - - case GL_REPLACE: - case GL_MODULATE: - case GL_ADD: - // these modes are best set with TexEnv, Combine4 would need much more setup - GL_TexEnv (pass->blendmode); - break; - - case GL_DECAL: - // mimics Alpha-Blending in upper texture stage, but instead of multiplying the alpha-channel, theyre added - // this way it can be possible to use GL_DECAL in both texture-units, while still looking good - // normal mutlitexturing would multiply the alpha-channel which looks ugly - GL_TexEnv (GL_COMBINE_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD); - - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); - - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); - - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA); - break; - - default: - GL_TexEnv (GL_COMBINE4_NV); - qglTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); - qglTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD); - - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); - - switch ( pass->blendsrc ) - { - case GL_ONE: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_ZERO); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA); - break; - case GL_ZERO: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_ZERO); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); - break; - case GL_DST_COLOR: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); - break; - case GL_ONE_MINUS_DST_COLOR: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA); - break; - case GL_SRC_ALPHA: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_ALPHA); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); - break; - case GL_ONE_MINUS_SRC_ALPHA: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA); - break; - case GL_DST_ALPHA: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_ALPHA); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); - break; - case GL_ONE_MINUS_DST_ALPHA: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA); - break; - } - - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA); - - switch (pass->blenddst) - { - case GL_ONE: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_ZERO); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA); - break; - case GL_ZERO: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_ZERO); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA); - break; - case GL_SRC_COLOR: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA); - break; - case GL_ONE_MINUS_SRC_COLOR: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA); - break; - case GL_SRC_ALPHA: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_ALPHA); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA); - break; - case GL_ONE_MINUS_SRC_ALPHA: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_ALPHA); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_TEXTURE); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA); - break; - case GL_DST_ALPHA: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_ALPHA); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA); - break; - case GL_ONE_MINUS_DST_ALPHA: - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_ALPHA); - qglTexEnvi (GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_PREVIOUS_EXT); - qglTexEnvi (GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA); - break; - } - break; - } - - R_ModifyTextureCoords ( pass, i ); - } - - R_FlushArraysMtex (); -} - -void R_RenderMeshProgram ( meshbuffer_t *mb, shaderpass_t *pass ) -{ - shader_t *s; - int i; - vec3_t param3; - int r, g, b; - - r_numUnits = pass->numMergedPasses; - - R_SetShaderpassState ( pass, true ); - R_ModifyColor ( mb, pass ); - - GL_SelectTexture( 0 ); - if ( pass->blendmode == GL_REPLACE ) - GL_TexEnv( GL_REPLACE ); - else - GL_TexEnv( GL_MODULATE ); - R_ModifyTextureCoords ( pass, 0 ); - - for ( i = 1, pass++; i < r_numUnits; i++, pass++ ) - { - GL_SelectTexture( i ); - - R_ModifyTextureCoords ( pass, i ); - } - - s = mb->shader; - GLSlang_UseProgram(s->programhandle); - for (i = 0; i < s->numprogparams; i++) - { - switch(s->progparm[i].type) - { - case SP_EYEPOS: - { - vec3_t t, v; - VectorSubtract(r_origin, currententity->origin, t); - - if (!Matrix3_Compare(currententity->axis, axisDefault)) - { - Matrix3_Multiply_Vec3(currententity->axis, t, v ); - } - else - { - VectorCopy(t, v); - } - qglUniform3fvARB(s->progparm[i].handle, 1, v); - } - break; - case SP_TIME: - qglUniform1fARB(s->progparm[i].handle, r_localShaderTime); - break; - - case SP_ENTCOLOURS: - qglUniform4fvARB(s->progparm[i].handle, 1, currententity->shaderRGBAf); - break; - case SP_TOPCOLOURS: - R_FetchTopColour(&r, &g, &b); - param3[0] = r/255; - param3[1] = g/255; - param3[2] = b/255; - qglUniform3fvARB(s->progparm[i].handle, 1, param3); - break; - case SP_BOTTOMCOLOURS: - R_FetchBottomColour(&r, &g, &b); - param3[0] = r/255; - param3[1] = g/255; - param3[2] = b/255; - qglUniform3fvARB(s->progparm[i].handle, 1, param3); - break; - - default: - Host_EndGame("Bad shader program parameter type (%i)", s->progparm[i].type); - break; - } - } - R_FlushArraysMtex (); - GLSlang_UseProgram(0); -} - -/* -================ -R_RenderMeshBuffer -================ -*/ -void R_RenderMeshBuffer ( meshbuffer_t *mb, qboolean shadowpass ) -{ - int i; - shader_t *shader; - shaderpass_t *pass; - - if ( !numVerts ) - { - return; - } - -// R_IBrokeTheArrays(); - -// qglVertexPointer( 3, GL_FLOAT, 16, vertexArray ); // padded for SIMD -// qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); - -// qglEnableClientState( GL_VERTEX_ARRAY ); - - shader = mb->shader; - r_lmtex = mb->infokey; - - if ( currententity && !gl_state.in2d ) - { - r_localShaderTime = r_refdef.time - currententity->shaderTime; - } else - { - r_localShaderTime = realtime; - } - - R_SetShaderState ( shader ); - - if ( shader->numdeforms ) - { - R_DeformVertices ( mb ); - } - - if ( !numIndexes || shadowpass ) - { - return; - } - - R_LockArrays ( numVerts ); - - for ( i = 0, pass = shader->passes; i < shader->numpasses; ) - { - if ( !(pass->flags & SHADER_PASS_DETAIL) || r_detailtextures.value ) - { - pass->flush ( mb, pass ); - } - - i += pass->numMergedPasses; - pass += pass->numMergedPasses; - } - - R_FinishMeshBuffer ( mb ); -} - - -/* -================ -R_RenderFogOnMesh -================ -*/ - -#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist) -void R_RenderFogOnMesh ( shader_t *shader, struct mfog_s *fog ) -{ -#define FOG_TEXTURE_HEIGHT 32 - - int i; - vec3_t diff, viewtofog, fog_vpn; - float dist, vdist; - shader_t *fogshader; - mplane_t *fogplane; - - if ( !fog->numplanes || !fog->shader || !fog->visibleplane ) - { - return; - } - - R_ResetTexState (); - - fogshader = fog->shader; - fogplane = fog->visibleplane; - - GL_Bind( r_fogtexture ); - - qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - GL_TexEnv(GL_MODULATE); - - if ( !shader || !shader->numpasses || shader->fog_dist || (shader->flags & SHADER_SKY) ) - { - extern int gldepthfunc; - qglDepthFunc ( gldepthfunc ); - } - else - { - qglDepthFunc ( GL_EQUAL ); - } - - qglColor4ubv ( fogshader->fog_color ); - - // distance to fog - dist = PlaneDiff ( r_origin, fogplane ); - - if ( shader && shader->flags & SHADER_SKY ) - { - if ( dist > 0 ) - VectorMA( r_origin, -dist, fogplane->normal, viewtofog ); - else - VectorCopy( r_origin, viewtofog ); - } - else - { - VectorCopy( currententity->origin, viewtofog ); - } - - VectorScale ( vpn, fogshader->fog_dist, fog_vpn ); - - for ( i = 0; i < numVerts; i++, currentCoords += 2 ) - { - VectorAdd ( viewtofog, vertexArray[i], diff ); - vdist = PlaneDiff ( diff, fogplane ); - VectorSubtract ( diff, r_origin, diff ); - - if ( dist < 0 ) - { // camera is inside the fog brush - currentCoords[0] = DotProduct ( diff, fog_vpn ); - } - else - { - if ( vdist < 0 ) - { - currentCoords[0] = vdist / ( vdist - dist ); - currentCoords[0] *= DotProduct ( diff, fog_vpn ); - } - else - { - currentCoords[0] = 0.0f; - } - } - - currentCoords[1] = -vdist * fogshader->fog_dist + 1.5f/(float)FOG_TEXTURE_HEIGHT; - } - - if ( shader && !shader->numpasses ) - { - R_LockArrays ( numVerts ); - } - - R_FlushArrays (); -} - -/* -================ -R_DrawTriangleOutlines -================ -*/ -void R_DrawTriangleOutlines (void) -{ - R_ResetTexState (); - - qglDisable( GL_TEXTURE_2D ); - qglDisable( GL_DEPTH_TEST ); - qglColor4f( 1, 1, 1, 1 ); - qglDisable ( GL_BLEND ); - qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - - R_FlushArrays (); - - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - qglEnable( GL_DEPTH_TEST ); - qglEnable( GL_TEXTURE_2D ); -} - -/* -================ -R_DrawNormals -================ -*/ -void R_DrawNormals (void) -{ - int i; - - R_ResetTexState(); - - qglDisable(GL_TEXTURE_2D); - qglColor4f(1, 1, 1, 1); - qglDisable(GL_BLEND); - - if (gl_state.in2d) - { - qglBegin(GL_POINTS); - for (i = 0; i < numVerts; i++) - { - qglVertex3fv(vertexArray[i]); - } - qglEnd(); - } - else - { - qglDisable(GL_DEPTH_TEST); - qglBegin(GL_LINES); - for (i = 0; i < numVerts; i++) - { - qglVertex3fv(vertexArray[i]); - qglVertex3f(vertexArray[i][0] + normalsArray[i][0], - vertexArray[i][1] + normalsArray[i][1], - vertexArray[i][2] + normalsArray[i][2]); - } - qglEnd(); - qglEnable(GL_DEPTH_TEST); - } - - qglEnable(GL_TEXTURE_2D); -} - -/* -================= -R_AddDynamicLights -================= -*/ -void R_AddDynamicLights ( meshbuffer_t *mb ) -{ - dlight_t *light; - int i, j, lnum; - vec3_t point, tvec, dlorigin; - vec3_t vright, vup; - vec3_t dir1, dir2, normal, right, up, oldnormal; - float *v[3], dist, scale; - index_t *oldIndexesArray, index[3]; - int dlightNumIndexes, oldNumIndexes; - - oldNumIndexes = numIndexes; - oldIndexesArray = indexesArray; - VectorClear ( oldnormal ); - - GL_Bind ( r_dlighttexture ); - - qglDepthFunc ( GL_EQUAL ); - qglBlendFunc ( GL_DST_COLOR, GL_ONE ); - GL_TexEnv(GL_MODULATE); - - light = cl_dlights; - for ( lnum = 0; lnum < 32; lnum++, light++ ) - { - if ( !(mb->dlightbits & (1<radius) - continue; //urm - - VectorSubtract ( light->origin, currententity->origin, dlorigin ); - if ( !Matrix3_Compare (currententity->axis, axisDefault) ) - { - VectorCopy ( dlorigin, point ); - Matrix3_Multiply_Vec3 ( currententity->axis, point, dlorigin ); - } - - qglColor4f (light->color[0]*2, light->color[1]*2, light->color[2]*2, 1);//light->color[3]); - - R_ResetTexState (); - dlightNumIndexes = 0; - - for ( i = 0; i < oldNumIndexes; i += 3 ) - { - index[0] = oldIndexesArray[i+0]; - index[1] = oldIndexesArray[i+1]; - index[2] = oldIndexesArray[i+2]; - - v[0] = (float *)(vertexArray + index[0]); - v[1] = (float *)(vertexArray + index[1]); - v[2] = (float *)(vertexArray + index[2]); - - // calculate two mostly perpendicular edge directions - VectorSubtract ( v[0], v[1], dir1 ); - VectorSubtract ( v[2], v[1], dir2 ); - - // we have two edge directions, we can calculate a third vector from - // them, which is the direction of the surface normal - CrossProduct ( dir1, dir2, normal ); - VectorNormalize ( normal ); - - VectorSubtract ( v[0], dlorigin, tvec ); - dist = DotProduct ( tvec, normal ); - if ( dist < 0 ) - dist = -dist; - if ( dist >= light->radius ) { - continue; - } - - VectorMA ( dlorigin, -dist, normal, point ); - scale = 1 / (light->radius - dist); - - if ( !VectorEquals (normal, oldnormal) ) { - MakeNormalVectors ( normal, right, up ); - VectorCopy ( normal, oldnormal ); - } - - VectorScale ( right, scale, vright ); - VectorScale ( up, scale, vup ); - - for ( j = 0; j < 3; j++ ) - { - // Get our texture coordinates - // Project the light image onto the face - VectorSubtract( v[j], point, tvec ); - - coordsArray[index[j]][0] = DotProduct( tvec, vright ) + 0.5f; - coordsArray[index[j]][1] = DotProduct( tvec, vup ) + 0.5f; - } - - tempIndexesArray[dlightNumIndexes++] = index[0]; - tempIndexesArray[dlightNumIndexes++] = index[1]; - tempIndexesArray[dlightNumIndexes++] = index[2]; - } - - if ( dlightNumIndexes ) - { - R_PushIndexes ( tempIndexesArray, NULL, NULL, dlightNumIndexes, MF_NONBATCHED ); - R_FlushArrays (); - dlightNumIndexes = 0; - } - } - - numIndexes = oldNumIndexes; - indexesArray = oldIndexesArray; -} - - -/* -================ -R_FinishMeshBuffer -Render dynamic lights, fog, triangle outlines, normals and clear arrays -================ -*/ -void R_FinishMeshBuffer ( meshbuffer_t *mb ) -{ - shader_t *shader; - qboolean fogged; - qboolean dlight; - - shader = mb->shader; - if ((mb->dlightbits != 0) && !(shader->flags & SHADER_FLARE)) - dlight = (currententity->model->type == mod_brush && currententity->model->fromgame == fg_quake3); - else - dlight = false; - - fogged = mb->fog && ((shader->sort < SHADER_SORT_UNDERWATER && - (shader->flags & (SHADER_DEPTHWRITE|SHADER_SKY))) || shader->fog_dist); - - if ( dlight || fogged ) { - GL_DisableMultitexture ( ); - qglTexCoordPointer( 2, GL_FLOAT, 0, inCoordsArray[0] ); - - qglEnable ( GL_BLEND ); - qglDisable ( GL_ALPHA_TEST ); - qglDepthMask ( GL_FALSE ); - - if (dlight) //HACK: the extra check is because we play with the lightmaps in q1/q2 - { - R_AddDynamicLights ( mb ); - } - - if (fogged) - { - R_RenderFogOnMesh ( shader, mb->fog ); - } - - qglDepthMask ( GL_TRUE ); - } - - if ( r_showtris.value || r_shownormals.value ) { - GL_DisableMultitexture ( ); - - if ( r_showtris.value ) { - R_DrawTriangleOutlines (); - } - - if ( r_shownormals.value ) { - R_DrawNormals (); - } - } - - R_UnlockArrays (); - R_ClearArrays (); -} - -#endif - - - - - - - -#endif - -#endif #endif diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 191005ac..d3ca2353 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -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; diff --git a/engine/gl/gl_draw.h b/engine/gl/gl_draw.h index 2f3a99ce..b894ea92 100644 --- a/engine/gl/gl_draw.h +++ b/engine/gl/gl_draw.h @@ -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); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 7e9276a6..6a40de41 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -3,6 +3,10 @@ #ifndef SERVERONLY #include "shader.h" +#ifdef _WIN32 +#include +#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]); diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index dd514dfe..01670ecf 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -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); diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index fcc0adb2..5eb1a47c 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -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); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 24c50e28..5847ca47 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -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 (); diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c index f5e2272e..935a498d 100644 --- a/engine/gl/gl_rmisc.c +++ b/engine/gl/gl_rmisc.c @@ -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 ; inumleafs ; 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) diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c index 261c3a4a..1b58e4c4 100644 --- a/engine/gl/gl_rsurf.c +++ b/engine/gl/gl_rsurf.c @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // r_surf.c: surface-related refresh code #include "quakedef.h" -#if defined(GLQUAKE) //|| defined(D3DQUAKE) +#if defined(GLQUAKE) #include "glquake.h" #include "shader.h" #include "renderque.h" @@ -28,2599 +28,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern cvar_t gl_bump; -static qbyte areabits[MAX_Q2MAP_AREAS/8]; - -model_t *currentmodel; - - -int lightmap_bytes; // 1, 3 or 4 - -texid_t *lightmap_textures; -texid_t *deluxmap_textures; - -#define MAX_LIGHTMAP_SIZE LMBLOCK_WIDTH - -vec3_t blocknormals[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE]; -unsigned blocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE]; -#ifdef PEXT_LIGHTSTYLECOL -unsigned greenblklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE]; -unsigned blueblklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE]; -#endif - -lightmapinfo_t **lightmap; -int numlightmaps; - -msurface_t *r_alpha_surfaces = NULL; -extern msurface_t *r_mirror_chain; - -mleaf_t *r_vischain; // linked list of visible leafs - -extern cvar_t gl_detail; -extern cvar_t r_stains; -extern cvar_t r_loadlits; -extern cvar_t r_stainfadetime; -extern cvar_t r_stainfadeammount; - -//extern cvar_t gl_lightmapmode; - -int GLR_LightmapShift (model_t *model) -{ - extern cvar_t gl_overbright_all, gl_lightmap_shift; - - if (gl_overbright_all.ival || (model->engineflags & MDLF_NEEDOVERBRIGHT)) - return bound(0, gl_lightmap_shift.ival, 2); - return 0; -} - -//radius, x y z, r g b -void GLR_StainSurf (msurface_t *surf, float *parms) -{ - int sd, td; - float dist, rad, minlight; - float change; - vec3_t impact, local; - int s, t; - int i; - int smax, tmax; - float amm; - int lim; - mtexinfo_t *tex; - stmap *stainbase; - - lim = 255 - (r_stains.value*255); - -#define stain(x) \ - change = stainbase[(s)*3+x] + amm*parms[4+x]; \ - stainbase[(s)*3+x] = bound(lim, change, 255); - - if (surf->lightmaptexturenum < 0) - return; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - tex = surf->texinfo; - - stainbase = lightmap[surf->lightmaptexturenum]->stainmaps; - stainbase += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * 3; - - rad = *parms; - dist = DotProduct ((parms+1), surf->plane->normal) - surf->plane->dist; - rad -= fabs(dist); - minlight = 0; - if (rad < minlight) //not hit - return; - minlight = rad - minlight; - - for (i=0 ; i<3 ; i++) - { - impact[i] = (parms+1)[i] - surf->plane->normal[i]*dist; - } - - local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; - local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; - - local[0] -= surf->texturemins[0]; - local[1] -= surf->texturemins[1]; - - for (t = 0 ; t td) - dist = sd + (td>>1); - else - dist = td + (sd>>1); - if (dist < minlight) - { - amm = (rad - dist); - stain(0); - stain(1); - stain(2); - - surf->stained = true; - } - } - stainbase += 3*LMBLOCK_WIDTH; - } - - if (surf->stained) - surf->cached_dlight=-1; -} - -//combination of R_AddDynamicLights and R_MarkLights -/* -static void GLR_StainNode (mnode_t *node, float *parms) -{ - mplane_t *splitplane; - float dist; - msurface_t *surf; - int i; - - if (node->contents < 0) - return; - - splitplane = node->plane; - dist = DotProduct ((parms+1), splitplane->normal) - splitplane->dist; - - if (dist > (*parms)) - { - GLR_StainNode (node->children[0], parms); - return; - } - if (dist < (-*parms)) - { - GLR_StainNode (node->children[1], parms); - return; - } - -// mark the polygons - surf = cl.worldmodel->surfaces + node->firstsurface; - for (i=0 ; inumsurfaces ; i++, surf++) - { - if (surf->flags&~(SURF_DONTWARP|SURF_PLANEBACK)) - continue; - GLR_StainSurf(surf, parms); - } - - GLR_StainNode (node->children[0], parms); - GLR_StainNode (node->children[1], parms); -} -*/ - -void GLR_AddStain(vec3_t org, float red, float green, float blue, float radius) -{ - physent_t *pe; - int i; - - float parms[7]; - if (!cl.worldmodel || cl.worldmodel->needload || r_stains.value <= 0) - return; - parms[0] = radius; - parms[1] = org[0]; - parms[2] = org[1]; - parms[3] = org[2]; - parms[4] = red; - parms[5] = green; - parms[6] = blue; - - - cl.worldmodel->funcs.StainNode(cl.worldmodel->nodes+cl.worldmodel->hulls[0].firstclipnode, parms); - - //now stain bsp models other than world. - - for (i=1 ; i< pmove.numphysent ; i++) //0 is world... - { - pe = &pmove.physents[i]; - if (pe->model && pe->model->surfaces == cl.worldmodel->surfaces) - { - parms[1] = org[0] - pe->origin[0]; - parms[2] = org[1] - pe->origin[1]; - parms[3] = org[2] - pe->origin[2]; - - if (pe->angles[0] || pe->angles[1] || pe->angles[2]) - { - vec3_t f, r, u, temp; - AngleVectors(pe->angles, f, r, u); - VectorCopy((parms+1), temp); - parms[1] = DotProduct(temp, f); - parms[2] = -DotProduct(temp, r); - parms[3] = DotProduct(temp, u); - } - - - pe->model->funcs.StainNode(pe->model->nodes+pe->model->hulls[0].firstclipnode, parms); - } - } -} - -void GLR_WipeStains(void) -{ - int i; - for (i = 0; i < numlightmaps; i++) - { - if (!lightmap[i]) - break; - memset(lightmap[i]->stainmaps, 255, sizeof(lightmap[i]->stainmaps)); - } -} - -void GLR_LessenStains(void) -{ - int i; - msurface_t *surf; - - int smax, tmax; - int s, t; - stmap *stain; - int stride; - int ammount; - int limit; - - static float time; - - if (!r_stains.value) - return; - - time += host_frametime; - if (time < r_stainfadetime.value) - return; - time-=r_stainfadetime.value; - - ammount = r_stainfadeammount.value; - limit = 255 - ammount; - - surf = cl.worldmodel->surfaces; - for (i=0 ; inumsurfaces ; i++, surf++) - { - if (surf->stained) - { - surf->cached_dlight=-1;//nice hack here... - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - - stain = lightmap[surf->lightmaptexturenum]->stainmaps; - stain += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * 3; - - stride = (LMBLOCK_WIDTH-smax)*3; - - surf->stained = false; - - smax*=3; - - for (t = 0 ; tstained=true; - } - else //reset to 255 - *stain = 255; - - stain++; - } - } - } - } -} - -/* -=============== -R_AddDynamicLights -=============== -*/ -static void GLR_AddDynamicLights (msurface_t *surf) -{ - int lnum; - int sd, td; - float dist, rad, minlight; - vec3_t impact, local; - int s, t; - int i; - int smax, tmax; - mtexinfo_t *tex; - float a; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - tex = surf->texinfo; - - for (lnum=rtlights_first; lnumdlightbits & (1<plane->normal) - - surf->plane->dist; - rad -= fabs(dist); - minlight = cl_dlights[lnum].minlight; - if (rad < minlight) - continue; - minlight = rad - minlight; - - for (i=0 ; i<3 ; i++) - { - impact[i] = cl_dlights[lnum].origin[i] - - surf->plane->normal[i]*dist; - } - - local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; - local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; - - local[0] -= surf->texturemins[0]; - local[1] -= surf->texturemins[1]; - - a = 256*(cl_dlights[lnum].color[0]*1.5 + cl_dlights[lnum].color[1]*2.95 + cl_dlights[lnum].color[2]*0.55); - - for (t = 0 ; t td) - dist = sd + (td>>1); - else - dist = td + (sd>>1); - if (dist < minlight) - blocklights[t*smax + s] += (rad - dist)*a; - } - } - } -} - -static void GLR_AddDynamicLightNorms (msurface_t *surf) -{ - int lnum; - int sd, td; - float dist, rad, minlight; - vec3_t impact, local; - int s, t; - int i; - int smax, tmax; - mtexinfo_t *tex; - float a; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - tex = surf->texinfo; - - for (lnum=rtlights_first; lnumdlightbits & (1<plane->normal) - - surf->plane->dist; - rad -= fabs(dist); - minlight = cl_dlights[lnum].minlight; - if (rad < minlight) - continue; - minlight = rad - minlight; - - for (i=0 ; i<3 ; i++) - { - impact[i] = cl_dlights[lnum].origin[i] - - surf->plane->normal[i]*dist; - } - - local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; - local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; - - local[0] -= surf->texturemins[0]; - local[1] -= surf->texturemins[1]; - - a = 256*(cl_dlights[lnum].color[0]*1.5 + cl_dlights[lnum].color[1]*2.95 + cl_dlights[lnum].color[2]*0.55); - - for (t = 0 ; t td) - dist = sd + (td>>1); - else - dist = td + (sd>>1); - if (dist < minlight) - { -// blocknormals[t*smax + s][0] -= (rad - dist)*(impact[0]-local[0])/8192.0; -// blocknormals[t*smax + s][1] -= (rad - dist)*(impact[1]-local[1])/8192.0; - blocknormals[t*smax + s][2] += 0.5*blocknormals[t*smax + s][2]*(rad - dist)/256; - } - } - } - } -} - -#ifdef PEXT_LIGHTSTYLECOL -static void GLR_AddDynamicLightsColours (msurface_t *surf) -{ - int lnum; - int sd, td; - float dist, rad, minlight; - vec3_t impact, local; - int s, t; - int i; - int smax, tmax; - mtexinfo_t *tex; -// float temp; - float r, g, b; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - tex = surf->texinfo; - - for (lnum=rtlights_first; lnumdlightbits & (1<plane->normal) - - surf->plane->dist; - rad -= fabs(dist); - minlight = cl_dlights[lnum].minlight; - if (rad < minlight) - continue; - minlight = rad - minlight; - - for (i=0 ; i<3 ; i++) - { - impact[i] = cl_dlights[lnum].origin[i] - - surf->plane->normal[i]*dist; - } - - local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; - local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; - - local[0] -= surf->texturemins[0]; - local[1] -= surf->texturemins[1]; - - r = cl_dlights[lnum].color[0]*3*256; - g = cl_dlights[lnum].color[1]*3*256; - b = cl_dlights[lnum].color[2]*3*256; - -/* if (cl_dlights[lnum].type == 1) //a wierd effect. - { - for (t = 0 ; t td) - dist = sd + (td>>1); - else - dist = td + (sd>>1); - if (dist < minlight) - { - blocklights[t*smax + s] += 2*sin(dist/10+cl.time*20)*(rad - dist)*256 * cl_dlights[lnum].colour[0]*3; - greenblklights[t*smax + s] += 2*sin(M_PI/3+dist/10+cl.time*20)*(rad - dist)*256 * cl_dlights[lnum].colour[1]*3; - blueblklights[t*smax + s] += 2*sin(2*M_PI/3+dist/10+cl.time*20)*(rad - dist)*256 * cl_dlights[lnum].colour[2]*3; - } - } - } - } - else - { -*/ for (t = 0 ; t td) - dist = sd + (td>>1); - else - dist = td + (sd>>1); - if (dist < minlight) - { - blocklights[t*smax + s] += (rad - dist)*r; - greenblklights[t*smax + s] += (rad - dist)*g; - blueblklights[t*smax + s] += (rad - dist)*b; - } - } - } -// } - } -} -#endif - - - -static void GLR_BuildDeluxMap (msurface_t *surf, qbyte *dest) -{ - int smax, tmax; - int i, j, size; - qbyte *lightmap; - qbyte *deluxmap; - unsigned scale; - int maps; - float intensity; - vec_t *bnorm; - vec3_t temp; - - int stride = LMBLOCK_WIDTH*3; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - size = smax*tmax; - lightmap = surf->samples; - - // set to full bright if no light data - if (!currentmodel->deluxdata) - { - for (i=0 ; iorientation[2][0]; - blocknormals[i][1] = 0.8;//surf->orientation[2][1]; - blocknormals[i][2] = 1;//surf->orientation[2][2]; - } - goto store; - } - - if (currentmodel->engineflags & MDLF_RGBLIGHTING) - deluxmap = surf->samples - currentmodel->lightdata + currentmodel->deluxdata; - else - deluxmap = (surf->samples - currentmodel->lightdata)*3 + currentmodel->deluxdata; - - -// clear to no light - for (i=0 ; iengineflags & MDLF_RGBLIGHTING) - { - deluxmap = surf->samples - currentmodel->lightdata + currentmodel->deluxdata; - - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; - maps++) - { - scale = d_lightstylevalue[surf->styles[maps]]; - for (i=0 ; isamples - currentmodel->lightdata)*3 + currentmodel->deluxdata; - - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; - maps++) - { - scale = d_lightstylevalue[surf->styles[maps]]; - for (i=0 ; idlightframe == r_framecount) -// GLR_AddDynamicLightNorms (surf); - -// bound, invert, and shift - - stride -= smax*3; - - bnorm = blocknormals[0]; - for (i=0 ; isamples && currentmodel->lightdata) - return; - - shift += 7; // increase to base value - surf->cached_dlight = (surf->dlightframe == r_framecount); - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - size = smax*tmax; - lightmap = surf->samples; - - if (size > MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE) - { //fixme: fill in? - Con_Printf("Lightmap too large\n"); - return; - } - - if (currentmodel->deluxdata) - GLR_BuildDeluxMap(surf, deluxdest); - - -#ifdef PEXT_LIGHTSTYLECOL - if (gl_lightmap_format == GL_RGBA || gl_lightmap_format == GL_RGB) - { - // set to full bright if no light data - if (r_fullbright.value>0) //not qw - { - for (i=0 ; idlightframe == r_framecount) - GLR_AddDynamicLightsColours (surf); - } - goto store; - } - if (!currentmodel->lightdata) - { - for (i=0 ; idlightframe == r_framecount) - GLR_AddDynamicLightsColours (surf); - goto store; - } - -// clear to no light - t = r_ambient.value*255; - for (i=0 ; ifromgame == fg_quake3) //rgb - { - /* for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; - maps++) //no light styles in q3 apparently. - { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; - } - */ - for (i = 0; i < tmax; i++) //q3 maps store their light in a block fashion, q1/q2/hl store it in a linear fashion. - { - for (j = 0; j < smax; j++) - { - blocklights[i*smax+j] = 255*lightmap[(i*LMBLOCK_WIDTH+j)*3]; - greenblklights[i*smax+j] = 255*lightmap[(i*LMBLOCK_WIDTH+j)*3+1]; - blueblklights[i*smax+j] = 255*lightmap[(i*LMBLOCK_WIDTH+j)*3+2]; - } - } -// memset(blocklights, 255, sizeof(blocklights)); - } - else if (currentmodel->engineflags & MDLF_RGBLIGHTING) //rgb - { - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; - maps++) - { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; - - - if (cl_lightstyle[surf->styles[maps]].colour == 7) //hopefully a faster alternative. - { - for (i=0 ; istyles[maps]].colour & 1) - for (i=0 ; istyles[maps]].colour & 2) - for (i=0 ; istyles[maps]].colour & 4) - for (i=0 ; istyles[maps] != 255 ; - maps++) - { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; - - if (cl_lightstyle[surf->styles[maps]].colour == 7) //hopefully a faster alternative. - { - for (i=0 ; istyles[maps]].colour & 1) - for (i=0 ; istyles[maps]].colour & 2) - for (i=0 ; istyles[maps]].colour & 4) - for (i=0 ; idlightframe == r_framecount) - GLR_AddDynamicLightsColours (surf); - } - else - { -#endif - // set to full bright if no light data - if (r_fullbright.value || !currentmodel->lightdata) - { - for (i=0 ; iengineflags & MDLF_RGBLIGHTING) //rgb - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; - maps++) - { - scale = d_lightstylevalue[surf->styles[maps]]/3; - surf->cached_light[maps] = scale; // 8.8 fraction - surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; - for (i=0 ; istyles[maps] != 255 ; - maps++) - { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colour; - for (i=0 ; idlightframe == r_framecount) - GLR_AddDynamicLights (surf); -#ifdef PEXT_LIGHTSTYLECOL - } -#endif - -// bound, invert, and shift -store: -#ifdef INVERTLIGHTMAPS - switch (gl_lightmap_format) - { -#ifdef PEXT_LIGHTSTYLECOL - case GL_RGBA: - stride -= (smax<<2); - bl = blocklights; - blg = greenblklights; - blb = blueblklights; - - if (!r_stains.value) - isstained = false; - else - isstained = surf->stained; - -/* if (!gl_lightcomponantreduction.value) - { - for (i=0 ; i>= 7; - if (t > 255) - dest[0] = 0; - else if (t < 0) - dest[0] = 256; - else - dest[0] = (255-t); - - t = *blg++; - t >>= 7; - if (t > 255) - dest[1] = 0; - else if (t < 0) - dest[1] = 256; - else - dest[1] = (255-t); - - t = *blb++; - t >>= 7; - if (t > 255) - dest[2] = 0; - else if (t < 0) - dest[2] = 256; - else - dest[2] = (255-t); - - dest[3] = 0;//(dest[0]+dest[1]+dest[2])/3; - dest += 4; - } - } - } - else -*/ { - stmap *stain; - for (i=0 ; i>= shift; - g >>= shift; - b >>= shift; - - if (isstained) // merge in stain - { - r = (127+r*(*stain++)) >> 8; - g = (127+g*(*stain++)) >> 8; - b = (127+b*(*stain++)) >> 8; - } - - cr = 0; - cg = 0; - cb = 0; - - if (r > 255) //ak too much red - { - cr -= (255-r)/2; - cg += (255-r)/4; //reduce it, and indicate to drop the others too. - cb += (255-r)/4; - r = 255; - } -// else if (r < 0) -// r = 0; - - if (g > 255) - { - cr += (255-g)/4; - cg -= (255-g)/2; - cb += (255-g)/4; - g = 255; - } -// else if (g < 0) -// g = 0; - - if (b > 255) - { - cr += (255-b)/4; - cg += (255-b)/4; - cb -= (255-b)/2; - b = 255; - } -// else if (b < 0) -// b = 0; - //* - if ((r+cr) > 255) - dest[0] = 0; //inverse lighting - else if ((r+cr) < 0) - dest[0] = 255; - else - dest[0] = 255-(r+cr); - - if ((g+cg) > 255) - dest[1] = 0; - else if ((g+cg) < 0) - dest[1] = 255; - else - dest[1] = 255-(g+cg); - - if ((b+cb) > 255) - dest[2] = 0; - else if ((b+cb) < 0) - dest[2] = 255; - else - dest[2] = 255-(b+cb); -/*/ - if ((r+cr) > 255) - dest[0] = 255; //non-inverse lighting - else if ((r+cr) < 0) - dest[0] = 0; - else - dest[0] = (r+cr); - - if ((g+cg) > 255) - dest[1] = 255; - else if ((g+cg) < 0) - dest[1] = 0; - else - dest[1] = (g+cg); - - if ((b+cb) > 255) - dest[2] = 255; - else if ((b+cb) < 0) - dest[2] = 0; - else - dest[2] = (b+cb); -*/ - - - - dest[3] = (dest[0]+dest[1]+dest[2])/3; //alpha?!?! - dest += 4; - } - } - } - break; - - case GL_RGB: - stride -= smax*3; - bl = blocklights; - blg = greenblklights; - blb = blueblklights; - - if (!r_stains.value) - isstained = false; - else - isstained = surf->stained; - -/* if (!gl_lightcomponantreduction.value) - { - for (i=0 ; i>= 7; - if (t > 255) - dest[0] = 0; - else if (t < 0) - dest[0] = 256; - else - dest[0] = (255-t); - - t = *blg++; - t >>= 7; - if (t > 255) - dest[1] = 0; - else if (t < 0) - dest[1] = 256; - else - dest[1] = (255-t); - - t = *blb++; - t >>= 7; - if (t > 255) - dest[2] = 0; - else if (t < 0) - dest[2] = 256; - else - dest[2] = (255-t); - - dest += 3; - } - } - } - else -*/ { - stmap *stain; - for (i=0 ; i>= shift; - g >>= shift; - b >>= shift; - - if (isstained) // merge in stain - { - r = (127+r*(*stain++)) >> 8; - g = (127+g*(*stain++)) >> 8; - b = (127+b*(*stain++)) >> 8; - } - - cr = 0; - cg = 0; - cb = 0; - - if (r > 255) //ak too much red - { - cr -= (255-r)/2; - cg += (255-r)/4; //reduce it, and indicate to drop the others too. - cb += (255-r)/4; - r = 255; - } -// else if (r < 0) -// r = 0; - - if (g > 255) - { - cr += (255-g)/4; - cg -= (255-g)/2; - cb += (255-g)/4; - g = 255; - } -// else if (g < 0) -// g = 0; - - if (b > 255) - { - cr += (255-b)/4; - cg += (255-b)/4; - cb -= (255-b)/2; - b = 255; - } -// else if (b < 0) -// b = 0; - //* - if ((r+cr) > 255) - dest[0] = 0; //inverse lighting - else if ((r+cr) < 0) - dest[0] = 255; - else - dest[0] = 255-(r+cr); - - if ((g+cg) > 255) - dest[1] = 0; - else if ((g+cg) < 0) - dest[1] = 255; - else - dest[1] = 255-(g+cg); - - if ((b+cb) > 255) - dest[2] = 0; - else if ((b+cb) < 0) - dest[2] = 255; - else - dest[2] = 255-(b+cb); -/*/ - if ((r+cr) > 255) - dest[0] = 255; //non-inverse lighting - else if ((r+cr) < 0) - dest[0] = 0; - else - dest[0] = (r+cr); - - if ((g+cg) > 255) - dest[1] = 255; - else if ((g+cg) < 0) - dest[1] = 0; - else - dest[1] = (g+cg); - - if ((b+cb) > 255) - dest[2] = 255; - else if ((b+cb) < 0) - dest[2] = 0; - else - dest[2] = (b+cb); -// */ - dest += 3; - } - } - } - break; -#else - case GL_RGBA: - stride -= (smax<<2); - bl = blocklights; - for (i=0 ; i>= shift; - if (t > 255) - t = 255; - dest[3] = 255-t; - dest += 4; - } - } - break; -#endif - case GL_ALPHA: - case GL_LUMINANCE: - case GL_INTENSITY: - bl = blocklights; - for (i=0 ; i>= shift; - if (t > 255) - t = 255; - dest[j] = 255-t; - } - } - break; - default: - Sys_Error ("Bad lightmap format"); - } -#else - switch (gl_lightmap_format) - { -#ifdef PEXT_LIGHTSTYLECOL - case GL_RGBA: - stride -= (smax<<2); - bl = blocklights; - blg = greenblklights; - blb = blueblklights; - - if (!r_stains.value) - isstained = false; - else - isstained = surf->stained; - -/* if (!gl_lightcomponantreduction.value) - { - for (i=0 ; i>= 7; - if (t > 255) - dest[0] = 0; - else if (t < 0) - dest[0] = 256; - else - dest[0] = (255-t); - - t = *blg++; - t >>= 7; - if (t > 255) - dest[1] = 0; - else if (t < 0) - dest[1] = 256; - else - dest[1] = (255-t); - - t = *blb++; - t >>= 7; - if (t > 255) - dest[2] = 0; - else if (t < 0) - dest[2] = 256; - else - dest[2] = (255-t); - - dest[3] = 0;//(dest[0]+dest[1]+dest[2])/3; - dest += 4; - } - } - } - else -*/ { - stmap *stain; - for (i=0 ; i>= shift; - g >>= shift; - b >>= shift; - - if (isstained) // merge in stain - { - r = (127+r*(*stain++)) >> 8; - g = (127+g*(*stain++)) >> 8; - b = (127+b*(*stain++)) >> 8; - } - - cr = 0; - cg = 0; - cb = 0; - - if (r > 255) //ak too much red - { - cr -= (255-r)/2; - cg += (255-r)/4; //reduce it, and indicate to drop the others too. - cb += (255-r)/4; - r = 255; - } -// else if (r < 0) -// r = 0; - - if (g > 255) - { - cr += (255-g)/4; - cg -= (255-g)/2; - cb += (255-g)/4; - g = 255; - } -// else if (g < 0) -// g = 0; - - if (b > 255) - { - cr += (255-b)/4; - cg += (255-b)/4; - cb -= (255-b)/2; - b = 255; - } -// else if (b < 0) -// b = 0; - //* - if ((r+cr) > 255) - dest[0] = 0; //inverse lighting - else if ((r+cr) < 0) - dest[0] = 255; - else - dest[0] = 255-(r+cr); - - if ((g+cg) > 255) - dest[1] = 0; - else if ((g+cg) < 0) - dest[1] = 255; - else - dest[1] = 255-(g+cg); - - if ((b+cb) > 255) - dest[2] = 0; - else if ((b+cb) < 0) - dest[2] = 255; - else - dest[2] = 255-(b+cb); -/*/ - if ((r+cr) > 255) - dest[0] = 255; //non-inverse lighting - else if ((r+cr) < 0) - dest[0] = 0; - else - dest[0] = (r+cr); - - if ((g+cg) > 255) - dest[1] = 255; - else if ((g+cg) < 0) - dest[1] = 0; - else - dest[1] = (g+cg); - - if ((b+cb) > 255) - dest[2] = 255; - else if ((b+cb) < 0) - dest[2] = 0; - else - dest[2] = (b+cb); -*/ - - - - dest[3] = (dest[0]+dest[1]+dest[2])/3; //alpha?!?! - dest += 4; - } - } - } - break; - - case GL_RGB: - stride -= smax*3; - bl = blocklights; - blg = greenblklights; - blb = blueblklights; - - if (!r_stains.value) - isstained = false; - else - isstained = surf->stained; - -/* if (!gl_lightcomponantreduction.value) - { - for (i=0 ; i>= 7; - if (t > 255) - dest[0] = 255; - else if (t < 0) - dest[0] = 0; - else - dest[0] = t; - - t = *blg++; - t >>= 7; - if (t > 255) - dest[1] = 255; - else if (t < 0) - dest[1] = 0; - else - dest[1] = t; - - t = *blb++; - t >>= 7; - if (t > 255) - dest[2] = 255; - else if (t < 0) - dest[2] = 0; - else - dest[2] = t; - - dest += 3; - } - } - } - else -*/ { - stmap *stain; - for (i=0 ; i>= shift; - g >>= shift; - b >>= shift; - - if (isstained) // merge in stain - { - r = (127+r*(*stain++)) >> 8; - g = (127+g*(*stain++)) >> 8; - b = (127+b*(*stain++)) >> 8; - } - - cr = 0; - cg = 0; - cb = 0; - - if (r > 255) //ak too much red - { - cr -= (255-r)/2; - cg += (255-r)/4; //reduce it, and indicate to drop the others too. - cb += (255-r)/4; - r = 255; - } -// else if (r < 0) -// r = 0; - - if (g > 255) - { - cr += (255-g)/4; - cg -= (255-g)/2; - cb += (255-g)/4; - g = 255; - } -// else if (g < 0) -// g = 0; - - if (b > 255) - { - cr += (255-b)/4; - cg += (255-b)/4; - cb -= (255-b)/2; - b = 255; - } -// else if (b < 0) -// b = 0; - //* - if ((r+cr) > 255) - dest[0] = 255; //inverse lighting - else if ((r+cr) < 0) - dest[0] = 0; - else - dest[0] = (r+cr); - - if ((g+cg) > 255) - dest[1] = 255; - else if ((g+cg) < 0) - dest[1] = 0; - else - dest[1] = (g+cg); - - if ((b+cb) > 255) - dest[2] = 255; - else if ((b+cb) < 0) - dest[2] = 0; - else - dest[2] = (b+cb); -/*/ - if ((r+cr) > 255) - dest[0] = 255; //non-inverse lighting - else if ((r+cr) < 0) - dest[0] = 0; - else - dest[0] = (r+cr); - - if ((g+cg) > 255) - dest[1] = 255; - else if ((g+cg) < 0) - dest[1] = 0; - else - dest[1] = (g+cg); - - if ((b+cb) > 255) - dest[2] = 255; - else if ((b+cb) < 0) - dest[2] = 0; - else - dest[2] = (b+cb); -// */ - dest += 3; - } - } - } - break; -#else - case GL_RGBA: - stride -= (smax<<2); - bl = blocklights; - for (i=0 ; i>= shift; - if (t > 255) - t = 255; - dest[3] = t; - dest += 4; - } - } - break; -#endif - case GL_ALPHA: - case GL_LUMINANCE: - case GL_INTENSITY: - bl = blocklights; - for (i=0 ; i>= shift; - if (t > 255) - t = 255; - dest[j] = t; - } - } - break; - default: - Sys_Error ("Bad lightmap format"); - } -#endif -} - - -/* -============================================================= - - BRUSH MODELS - -============================================================= -*/ - - -extern float speedscale; // for top sky and bottom sky - - -qboolean mtexenabled = false; - - -void GL_DisableMultitexture(void) -{ - if (mtexenabled) { - qglDisable(GL_TEXTURE_2D); - GL_SelectTexture(0); - mtexenabled = false; - } -} - -void GL_EnableMultitexture(void) -{ - if (gl_mtexable) { - GL_SelectTexture(1); - qglEnable(GL_TEXTURE_2D); - mtexenabled = true; - } -} - -/* -================ -R_RenderDynamicLightmaps -Multitexture -================ -*/ -void R_RenderDynamicLightmaps (msurface_t *fa, int shift) -{ - qbyte *base, *luxbase; - stmap *stainbase; - int maps; - glRect_t *theRect; - int smax, tmax; - - if (!fa->mesh) - return; - - c_brush_polys++; - - if (fa->lightmaptexturenum<0) - return; - - if (fa->flags & ( SURF_DRAWSKY | SURF_DRAWTURB) ) - return; - - if (fa->texinfo->flags & (TI_SKY|TI_TRANS33|TI_TRANS66|TI_WARP)) - return; - - if (fa->texinfo->flags & (TEX_SPECIAL)) - { - if (cl.worldmodel->fromgame == fg_halflife) - return; //some textures do this. - } - -// fa->polys->chain = lightmap[fa->lightmaptexturenum]->polys; -// lightmap[fa->lightmaptexturenum]->polys = fa->polys; - - // check for lightmap modification -// if (cl.worldmodel->fromgame != fg_quake3) //no lightstyles on q3 maps - { - for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ; - maps++) - if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] - #ifdef PEXT_LIGHTSTYLECOL - || cl_lightstyle[fa->styles[maps]].colour != fa->cached_colour[maps] - #endif - ) - goto dynamic; - } - - if (fa->dlightframe == r_framecount // dynamic this frame - || fa->cached_dlight) // dynamic previously - { - RSpeedLocals(); -dynamic: - RSpeedRemark(); - - lightmap[fa->lightmaptexturenum]->modified = true; - - smax = (fa->extents[0]>>4)+1; - tmax = (fa->extents[1]>>4)+1; - - theRect = &lightmap[fa->lightmaptexturenum]->rectchange; - if (fa->light_t < theRect->t) { - if (theRect->h) - theRect->h += theRect->t - fa->light_t; - theRect->t = fa->light_t; - } - if (fa->light_s < theRect->l) { - if (theRect->w) - theRect->w += theRect->l - fa->light_s; - theRect->l = fa->light_s; - } - if ((theRect->w + theRect->l) < (fa->light_s + smax)) - theRect->w = (fa->light_s-theRect->l)+smax; - if ((theRect->h + theRect->t) < (fa->light_t + tmax)) - theRect->h = (fa->light_t-theRect->t)+tmax; - - if (gl_bump.ival) - { - lightmap[fa->lightmaptexturenum]->deluxmodified = true; - theRect = &lightmap[fa->lightmaptexturenum]->deluxrectchange; - if (fa->light_t < theRect->t) { - if (theRect->h) - theRect->h += theRect->t - fa->light_t; - theRect->t = fa->light_t; - } - if (fa->light_s < theRect->l) { - if (theRect->w) - theRect->w += theRect->l - fa->light_s; - theRect->l = fa->light_s; - } - - if ((theRect->w + theRect->l) < (fa->light_s + smax)) - theRect->w = (fa->light_s-theRect->l)+smax; - if ((theRect->h + theRect->t) < (fa->light_t + tmax)) - theRect->h = (fa->light_t-theRect->t)+tmax; - - luxbase = lightmap[fa->lightmaptexturenum]->deluxmaps; - luxbase += fa->light_t * LMBLOCK_WIDTH * 3 + fa->light_s * 3; - } - else - luxbase = NULL; - - - base = lightmap[fa->lightmaptexturenum]->lightmaps; - base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes; - stainbase = lightmap[fa->lightmaptexturenum]->stainmaps; - stainbase += (fa->light_t * LMBLOCK_WIDTH + fa->light_s) * 3; - GLR_BuildLightMap (fa, base, luxbase, stainbase, shift); - - RSpeedEnd(RSPEED_DYNAMIC); - } -} - -/* -================ -R_MirrorChain -================ -*/ -void R_MirrorChain (msurface_t *s) -{ - if (mirror) - return; - r_mirror_chain = s; - mirror = true; - mirror_plane = s->plane; -} - -/* -============================================================= - - WORLD MODEL - -============================================================= -*/ - -qbyte *R_MarkLeafSurfaces_Q1 (void) -{ - qbyte *vis; - mleaf_t *leaf; - int i, j; - msurface_t *surf; - int shift; - - vis = R_CalcVis_Q1(); - - for (i=0 ; inumleafs ; i++) - { - if (vis[i>>3] & (1<<(i&7))) - { - leaf = (mleaf_t *)&cl.worldmodel->leafs[i+1]; - - if (R_CullBox (leaf->minmaxs, leaf->minmaxs+3)) - continue; - leaf->visframe = r_visframecount; - - for (j = 0; j < leaf->nummarksurfaces; j++) - { - surf = leaf->firstmarksurface[j]; - if (surf->visframe == r_visframecount) - continue; - surf->visframe = r_visframecount; - - *surf->mark = surf; - } - - //deal with static ents. - if (leaf->efrags) - R_StoreEfrags (&leaf->efrags); - } - } - - { - texture_t *tex; - - shift = GLR_LightmapShift(cl.worldmodel); - - for (i = 0; i < cl.worldmodel->numtextures; i++) - { - tex = cl.worldmodel->textures[i]; - if (!tex) - continue; - for (j = 0; j < tex->vbo.meshcount; j++) - { - surf = tex->vbo.meshlist[j]; - if (surf) - { - R_RenderDynamicLightmaps (surf, shift); - - tex->vbo.meshlist[j] = NULL; - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf; - } - } - } - } - return vis; -} - -/* -================ -R_RecursiveWorldNode -================ -*/ -static void GLR_RecursiveWorldNode (mnode_t *node, unsigned int clipflags) -{ - int c, side, clipped; - mplane_t *plane, *clipplane; - msurface_t *surf, **mark; - mleaf_t *pleaf; - double dot; - int shift; - -start: - - if (node->contents == Q1CONTENTS_SOLID) - return; // solid - - if (node->visframe != r_visframecount) - return; - - for (c = 0, clipplane = frustum; c < 4; c++, clipplane++) - { - if (!(clipflags & (1 << c))) - continue; // don't need to clip against it - - clipped = BOX_ON_PLANE_SIDE (node->minmaxs, node->minmaxs + 3, clipplane); - if (clipped == 2) - return; - else if (clipped == 1) - clipflags -= (1<contents < 0) - { - pleaf = (mleaf_t *)node; - - mark = pleaf->firstmarksurface; - c = pleaf->nummarksurfaces; - - if (c) - { - do - { - (*mark++)->visframe = r_framecount; - } while (--c); - } - - // deal with model fragments in this leaf - if (pleaf->efrags) - R_StoreEfrags (&pleaf->efrags); - return; - } - -// node is just a decision point, so go down the apropriate sides - -// find which side of the node we are on - plane = node->plane; - - switch (plane->type) - { - case PLANE_X: - dot = modelorg[0] - plane->dist; - break; - case PLANE_Y: - dot = modelorg[1] - plane->dist; - break; - case PLANE_Z: - dot = modelorg[2] - plane->dist; - break; - default: - dot = DotProduct (modelorg, plane->normal) - plane->dist; - break; - } - - if (dot >= 0) - side = 0; - else - side = 1; - -// recurse down the children, front side first - GLR_RecursiveWorldNode (node->children[side], clipflags); - -// draw stuff - c = node->numsurfaces; - - if (c) - { - surf = cl.worldmodel->surfaces + node->firstsurface; - - shift = GLR_LightmapShift(cl.worldmodel); - - if (dot < 0 -BACKFACE_EPSILON) - side = SURF_PLANEBACK; - else if (dot > BACKFACE_EPSILON) - side = 0; - { - for ( ; c ; c--, surf++) - { - if (surf->visframe != r_framecount) - continue; - - if (((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))) - continue; // wrong side - - R_RenderDynamicLightmaps (surf, shift); - // if sorting by texture, just store it out -/* if (surf->flags & SURF_DRAWALPHA) - { // add to the translucent chain - surf->nextalphasurface = r_alpha_surfaces; - r_alpha_surfaces = surf; - surf->ownerent = &r_worldentity; - } - else -*/ { - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf; - } - } - } - } - -// recurse down the back side - //GLR_RecursiveWorldNode (node->children[!side], clipflags); - node = node->children[!side]; - goto start; -} - -#ifdef Q2BSPS -static void GLR_RecursiveQ2WorldNode (mnode_t *node) -{ - int c, side; - mplane_t *plane; - msurface_t *surf, **mark; - mleaf_t *pleaf; - double dot; - int shift; - - int sidebit; - - if (node->contents == Q2CONTENTS_SOLID) - return; // solid - - if (node->visframe != r_visframecount) - return; - if (R_CullBox (node->minmaxs, node->minmaxs+3)) - return; - -// if a leaf node, draw stuff - if (node->contents != -1) - { - pleaf = (mleaf_t *)node; - - // check for door connected areas -// if (areabits) - { - if (! (areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) ) - return; // not visible - } - - mark = pleaf->firstmarksurface; - c = pleaf->nummarksurfaces; - - if (c) - { - do - { - (*mark)->visframe = r_framecount; - mark++; - } while (--c); - } - return; - } - -// node is just a decision point, so go down the apropriate sides - -// find which side of the node we are on - plane = node->plane; - - switch (plane->type) - { - case PLANE_X: - dot = modelorg[0] - plane->dist; - break; - case PLANE_Y: - dot = modelorg[1] - plane->dist; - break; - case PLANE_Z: - dot = modelorg[2] - plane->dist; - break; - default: - dot = DotProduct (modelorg, plane->normal) - plane->dist; - break; - } - - if (dot >= 0) - { - side = 0; - sidebit = 0; - } - else - { - side = 1; - sidebit = SURF_PLANEBACK; - } - -// recurse down the children, front side first - GLR_RecursiveQ2WorldNode (node->children[side]); - - shift = GLR_LightmapShift(currentmodel); - - // draw stuff - for ( c = node->numsurfaces, surf = currentmodel->surfaces + node->firstsurface; c ; c--, surf++) - { - if (surf->visframe != r_framecount) - continue; - - if ( (surf->flags & SURF_PLANEBACK) != sidebit ) - continue; // wrong side - - surf->visframe = r_framecount+1;//-1; - - R_RenderDynamicLightmaps (surf, shift); - - if (surf->texinfo->flags & (TI_TRANS33|TI_TRANS66)) - { // add to the translucent chain - surf->nextalphasurface = r_alpha_surfaces; - r_alpha_surfaces = surf; - surf->ownerent = &r_worldentity; - continue; - } - - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf; - } - - -// recurse down the back side - GLR_RecursiveQ2WorldNode (node->children[!side]); -} -#endif - -#ifdef Q3BSPS -mleaf_t *r_vischain; // linked list of visible leafs -static void GLR_LeafWorldNode (void) -{ - int i; - int clipflags; - msurface_t **mark, *surf; - mleaf_t *pleaf; - - - int clipped; - mplane_t *clipplane; - - - for (pleaf = r_vischain; pleaf; pleaf = pleaf->vischain) - { - // check for door connected areas -// if (areabits) - { -// if (!(areabits[pleaf->area>>3] & (1<<(pleaf->area&7)))) -// { -// continue; // not visible -// } - } - - clipflags = 15; // 1 | 2 | 4 | 8 -// if (!r_nocull->value) - { - - for (i=0,clipplane=frustum ; i<4 ; i++,clipplane++) - { - clipped = BoxOnPlaneSide (pleaf->minmaxs, pleaf->minmaxs+3, clipplane); - if (clipped == 2) - { - break; - } - else if (clipped == 1) - { - clipflags &= ~(1<nummarksurfaces; - mark = pleaf->firstmarksurface; - - do - { - surf = *mark++; - if (surf->visframe != r_framecount) //sufraces exist in multiple leafs. - { - surf->visframe = r_framecount; - if (surf->mark) - *surf->mark = surf; - /* - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf;# - */ - } - } while (--i); - -// c_world_leafs++; - } - - - - - { - int j; - texture_t *tex; - for (i = 0; i < cl.worldmodel->numtextures; i++) - { - tex = cl.worldmodel->textures[i]; - if (!tex) - continue; - for (j = 0; j < tex->vbo.meshcount; j++) - { - surf = tex->vbo.meshlist[j]; - if (surf) - { - tex->vbo.meshlist[j] = NULL; - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf; - } - } - } - } -} -#endif - -static void GLR_ClearChains(void) -{ - int i; - for (i = 0; i < cl.worldmodel->numtextures; i++) - { - if (!cl.worldmodel->textures[i]) - continue; - cl.worldmodel->textures[i]->texturechain = NULL; - cl.worldmodel->textures[i]->texturechain_tail = &cl.worldmodel->textures[i]->texturechain; - } -} -/* -============= -R_DrawWorld -============= -*/ - -void R_DrawWorld (void) -{ - qbyte *vis; - RSpeedLocals(); - entity_t ent; - - memset (&ent, 0, sizeof(ent)); - ent.model = cl.worldmodel; - currentmodel = cl.worldmodel; - - VectorCopy (r_refdef.vieworg, modelorg); - - currententity = &ent; -#ifdef TERRAIN - if (currentmodel->type == mod_heightmap) - GL_DrawHeightmapModel(currententity); - else -#endif - { - GLR_ClearChains(); - - RSpeedRemark(); - -#ifdef Q2BSPS - if (ent.model->fromgame == fg_quake2 || ent.model->fromgame == fg_quake3) - { - int leafnum; - int clientarea; -#ifdef QUAKE2 - if (cls.protocol == CP_QUAKE2) //we can get server sent info - memcpy(areabits, cl.q2frame.areabits, sizeof(areabits)); - else -#endif - { //generate the info each frame. - leafnum = CM_PointLeafnum (cl.worldmodel, r_refdef.vieworg); - clientarea = CM_LeafArea (cl.worldmodel, leafnum); - CM_WriteAreaBits(cl.worldmodel, areabits, clientarea); - } -#ifdef Q3BSPS - if (ent.model->fromgame == fg_quake3) - { - vis = R_MarkLeaves_Q3 (); - GLR_LeafWorldNode (); - } - else -#endif - { - vis = R_MarkLeaves_Q2 (); - GLR_RecursiveQ2WorldNode (cl.worldmodel->nodes); - } - } - else -#endif - { - extern cvar_t temp1; - if (1)//temp1.value) - vis = R_MarkLeafSurfaces_Q1(); - else - { - vis = R_MarkLeaves_Q1 (); - GLR_RecursiveWorldNode (cl.worldmodel->nodes, 0xf); - } - } - - RSpeedEnd(RSPEED_WORLDNODE); - TRACE(("dbg: calling PPL_DrawWorld\n")); -// if (r_shadows.value >= 2 && gl_canstencil && gl_mtexable) - PPL_DrawWorld(vis); -// else -// DrawTextureChains (cl.worldmodel, 1, r_refdef.vieworg); - - GLR_LessenStains(); - } -} - - - -/* -============================================================================= - - LIGHTMAP ALLOCATION - -============================================================================= -*/ - -// returns a texture number and the position inside it -int GLAllocBlock (int w, int h, int *x, int *y) -{ - int i, j; - int best, best2; - int texnum; - - for (texnum=0 ; ; texnum++) - { - if (texnum == numlightmaps) //allocate 4 more lightmap slots. not much memory usage, but we don't want any caps here. - { - lightmap = BZ_Realloc(lightmap, sizeof(*lightmap)*(numlightmaps+4)); - lightmap[numlightmaps+0] = NULL; - lightmap[numlightmaps+1] = NULL; - lightmap[numlightmaps+2] = NULL; - lightmap[numlightmaps+3] = NULL; - - lightmap_textures = BZ_Realloc(lightmap_textures, sizeof(*lightmap_textures)*(numlightmaps+4)); - lightmap_textures[numlightmaps+0] = GL_AllocNewTexture(); - lightmap_textures[numlightmaps+1] = GL_AllocNewTexture(); - lightmap_textures[numlightmaps+2] = GL_AllocNewTexture(); - lightmap_textures[numlightmaps+3] = GL_AllocNewTexture(); - - deluxmap_textures = BZ_Realloc(deluxmap_textures, sizeof(*deluxmap_textures)*(numlightmaps+4)); - deluxmap_textures[numlightmaps+0] = GL_AllocNewTexture(); - deluxmap_textures[numlightmaps+1] = GL_AllocNewTexture(); - deluxmap_textures[numlightmaps+2] = GL_AllocNewTexture(); - deluxmap_textures[numlightmaps+3] = GL_AllocNewTexture(); - numlightmaps+=4; - } - if (!lightmap[texnum]) - { - lightmap[texnum] = Z_Malloc(sizeof(*lightmap[texnum])); - lightmap[texnum]->meshchain = NULL; - lightmap[texnum]->modified = true; - // reset stainmap since it now starts at 255 - memset(lightmap[texnum]->stainmaps, 255, sizeof(lightmap[texnum]->stainmaps)); - - //clear out the deluxmaps incase there is none on the map. - for (j = 0; j < LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3; j+=3) - { - lightmap[texnum]->deluxmaps[j+0] = 128; - lightmap[texnum]->deluxmaps[j+1] = 128; - lightmap[texnum]->deluxmaps[j+2] = 255; - } - } - - - best = LMBLOCK_HEIGHT; - - for (i=0 ; iallocated[i+j] >= best) - break; - if (lightmap[texnum]->allocated[i+j] > best2) - best2 = lightmap[texnum]->allocated[i+j]; - } - if (j == w) - { // this is a valid spot - *x = i; - *y = best = best2; - } - } - - if (best + h > LMBLOCK_HEIGHT) - continue; - - for (i=0 ; iallocated[*x + i] = best + h; - - return texnum; - } - - Sys_Error ("AllocBlock: full"); - return 0; -} - -//quake3 maps have their lightmaps in gl style already. -//rather than forgetting that and redoing it, let's just keep the data. -int GLFillBlock (int texnum, int w, int h, int x, int y) -{ - int i, l; - while (texnum >= numlightmaps) //allocate 4 more lightmap slots. not much memory usage, but we don't want any caps here. - { - lightmap = BZ_Realloc(lightmap, sizeof(*lightmap)*(numlightmaps+4)); - lightmap[numlightmaps+0] = NULL; - lightmap[numlightmaps+1] = NULL; - lightmap[numlightmaps+2] = NULL; - lightmap[numlightmaps+3] = NULL; - - lightmap_textures = BZ_Realloc(lightmap_textures, sizeof(*lightmap_textures)*(numlightmaps+4)); - lightmap_textures[numlightmaps+0] = GL_AllocNewTexture(); - lightmap_textures[numlightmaps+1] = GL_AllocNewTexture(); - lightmap_textures[numlightmaps+2] = GL_AllocNewTexture(); - lightmap_textures[numlightmaps+3] = GL_AllocNewTexture(); - - deluxmap_textures = BZ_Realloc(deluxmap_textures, sizeof(*deluxmap_textures)*(numlightmaps+4)); - deluxmap_textures[numlightmaps+0] = GL_AllocNewTexture(); - deluxmap_textures[numlightmaps+1] = GL_AllocNewTexture(); - deluxmap_textures[numlightmaps+2] = GL_AllocNewTexture(); - deluxmap_textures[numlightmaps+3] = GL_AllocNewTexture(); - numlightmaps+=4; - } - for (i = texnum; i >= 0; i--) - { - if (!lightmap[i]) - { - lightmap[i] = BZ_Malloc(sizeof(*lightmap[i])); - lightmap[i]->meshchain = NULL; - lightmap[i]->modified = true; - for (l=0 ; lallocated[l] = LMBLOCK_HEIGHT; - } - - //clear out the deluxmaps incase there is none on the map. - for (l = 0; l < LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3; l+=3) - { - lightmap[i]->deluxmaps[l+0] = 0; - lightmap[i]->deluxmaps[l+1] = 0; - lightmap[i]->deluxmaps[l+2] = 255; - } - - //maybe someone screwed with my lightmap... - memset(lightmap[i]->lightmaps, 255, LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3); - if (cl.worldmodel->lightdata) - { - memcpy(lightmap[i]->lightmaps, cl.worldmodel->lightdata+3*LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*i, LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3); - } - else - { - char basename[MAX_QPATH]; - COM_StripExtension(cl.worldmodel->name, basename, sizeof(basename)); - lightmap_textures[i] = R_LoadHiResTexture(va("%s/lm_%04i", basename, i), NULL, IF_NOALPHA|IF_NOGAMMA); - lightmap[i]->modified = false; - } - - } - else - break; - } - return texnum; -} - -mvertex_t *r_pcurrentvertbase; - -int nColinElim; - -/* -================ -BuildSurfaceDisplayList -================ -*/ -void GL_BuildSurfaceDisplayList (msurface_t *fa) -{ - int i, lindex, lnumverts; - medge_t *pedges, *r_pedge; - int vertpage; - float *vec; - float s, t; - int lm; - -// reconstruct the polygon - pedges = currentmodel->edges; - lnumverts = fa->numedges; - vertpage = 0; - - if (lnumverts<3) - return; //q3 flares. - - { //build a nice mesh instead of a poly. - int size = sizeof(mesh_t) + sizeof(index_t)*(lnumverts-2)*3 + (sizeof(vecV_t) + 3*sizeof(vec3_t) + 2*sizeof(vec2_t) + sizeof(vec4_t))*lnumverts; - mesh_t *mesh; - - fa->mesh = mesh = Hunk_Alloc(size); - mesh->xyz_array = (vecV_t*)(mesh + 1); - mesh->normals_array = (vec3_t*)(mesh->xyz_array + lnumverts); - mesh->snormals_array = (vec3_t*)(mesh->normals_array + lnumverts); - mesh->tnormals_array = (vec3_t*)(mesh->snormals_array + lnumverts); - mesh->st_array = (vec2_t*)(mesh->tnormals_array + lnumverts); - mesh->lmst_array = (vec2_t*)(mesh->st_array + lnumverts); - mesh->colors4f_array = (vec4_t*)(mesh->lmst_array + lnumverts); - mesh->indexes = (index_t*)(mesh->colors4f_array + lnumverts); - - mesh->numindexes = (lnumverts-2)*3; - mesh->numvertexes = lnumverts; - mesh->istrifan = true; - - for (i=0 ; iindexes[i*3] = 0; - mesh->indexes[i*3+1] = i+1; - mesh->indexes[i*3+2] = i+2; - } - - for (i=0 ; isurfedges[fa->firstedge + i]; - - if (lindex > 0) - { - r_pedge = &pedges[lindex]; - vec = r_pcurrentvertbase[r_pedge->v[0]].position; - } - else - { - r_pedge = &pedges[-lindex]; - vec = r_pcurrentvertbase[r_pedge->v[1]].position; - } - - s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; - t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; - - VectorCopy (vec, mesh->xyz_array[i]); - mesh->st_array[i][0] = s/fa->texinfo->texture->width; - mesh->st_array[i][1] = t/fa->texinfo->texture->height; - - s -= fa->texturemins[0]; - lm = s*fa->light_t; - s += fa->light_s*16; - s += 8; - s /= LMBLOCK_WIDTH*16; - - t -= fa->texturemins[1]; - lm += t; - t += fa->light_t*16; - t += 8; - t /= LMBLOCK_HEIGHT*16; - - mesh->lmst_array[i][0] = s; - mesh->lmst_array[i][1] = t; - - if (fa->flags & SURF_PLANEBACK) - VectorNegate(fa->plane->normal, mesh->normals_array[i]); - else - VectorCopy(fa->plane->normal, mesh->normals_array[i]); - VectorNegate(fa->texinfo->vecs[0], mesh->snormals_array[i]); - VectorNegate(fa->texinfo->vecs[1], mesh->tnormals_array[i]); - VectorNormalize(mesh->snormals_array[i]); - VectorNormalize(mesh->tnormals_array[i]); - - mesh->colors4f_array[i][0] = 1; - mesh->colors4f_array[i][1] = 1; - mesh->colors4f_array[i][2] = 1; - mesh->colors4f_array[i][3] = 1; - } - } -} - -/* -======================== -GL_CreateSurfaceLightmap -======================== -*/ -void GL_CreateSurfaceLightmap (msurface_t *surf, int shift) -{ - int smax, tmax; - qbyte *base, *luxbase; stmap *stainbase; - - if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) - surf->lightmaptexturenum = -1; - if (surf->texinfo->flags & TEX_SPECIAL) - surf->lightmaptexturenum = -1; - if (surf->lightmaptexturenum<0) - return; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - - if (smax > LMBLOCK_WIDTH || tmax > LMBLOCK_HEIGHT || smax < 0 || tmax < 0) - { //whoa, buggy. - surf->lightmaptexturenum = -1; - return; - } - - if (currentmodel->fromgame == fg_quake3) - GLFillBlock(surf->lightmaptexturenum, smax, tmax, surf->light_s, surf->light_t); - else - surf->lightmaptexturenum = GLAllocBlock (smax, tmax, &surf->light_s, &surf->light_t); - base = lightmap[surf->lightmaptexturenum]->lightmaps; - base += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * lightmap_bytes; - - luxbase = lightmap[surf->lightmaptexturenum]->deluxmaps; - luxbase += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * 3; - - stainbase = lightmap[surf->lightmaptexturenum]->stainmaps; - stainbase += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * 3; - - GLR_BuildLightMap (surf, base, luxbase, stainbase, shift); -} - - - -void GLSurf_DeInit(void) -{ - int i; - for (i = 0; i < numlightmaps; i++) - { - if (!lightmap[i]) - break; - BZ_Free(lightmap[i]); - lightmap[i] = NULL; - } - - if (lightmap_textures) - { - for (i = 0; i < numlightmaps; i++) - qglDeleteTextures(1, &lightmap_textures[i].num); - BZ_Free(lightmap_textures); - } - if (lightmap) - BZ_Free(lightmap); - - lightmap_textures=NULL; - lightmap=NULL; - numlightmaps=0; -} void BE_ClearVBO(vbo_t *vbo) { @@ -2649,7 +56,7 @@ void BE_ClearVBO(vbo_t *vbo) memset(vbo, 0, sizeof(*vbo)); } -qboolean GL_BuildVBO(vbo_t *vbo, void *vdata, int vsize, void *edata, int elementsize) +static qboolean GL_BuildVBO(vbo_t *vbo, void *vdata, int vsize, void *edata, int elementsize) { unsigned int vbos[2]; @@ -2716,7 +123,7 @@ qboolean GL_BuildVBO(vbo_t *vbo, void *vdata, int vsize, void *edata, int elemen return true; } -static void GL_GenBrushModelVBO(model_t *mod) +void BE_GenBrushModelVBO(model_t *mod) { unsigned int maxvboverts; unsigned int maxvboelements; @@ -2758,8 +165,10 @@ static void GL_GenBrushModelVBO(model_t *mod) maxvboelements += m->numindexes; maxvboverts += m->numvertexes; } +#if sizeof_index_t == 2 if (maxvboverts > (1<<(sizeof(index_t)*8))-1) continue; +#endif if (!maxvboverts) continue; @@ -2864,124 +273,9 @@ static void GL_GenBrushModelVBO(model_t *mod) } } -/* -================== -GL_BuildLightmaps - -Builds the lightmap texture -with all the surfaces from all brush models -================== -*/ -void GL_BuildLightmaps (void) +void BE_UploadAllLightmaps(void) { - int i, j, t; - model_t *m; - int shift; - - r_framecount = 1; // no dlightcache - - for (i = 0; i < numlightmaps; i++) - { - if (!lightmap[i]) - break; - BZ_Free(lightmap[i]); - lightmap[i] = NULL; - } - - if (cl.worldmodel->fromgame == fg_doom) - return; //no lightmaps. - - if ((cl.worldmodel->engineflags & MDLF_RGBLIGHTING) || cl.worldmodel->deluxdata || r_loadlits.value) - gl_lightmap_format = GL_RGB; - else - gl_lightmap_format = GL_LUMINANCE; - -/* - if (COM_CheckParm ("-lm_1")) - gl_lightmap_format = GL_LUMINANCE; - if (COM_CheckParm ("-lm_a")) - gl_lightmap_format = GL_ALPHA; - if (COM_CheckParm ("-lm_i")) - gl_lightmap_format = GL_INTENSITY; - if (COM_CheckParm ("-lm_3")) - gl_lightmap_format = GL_RGB; - if (COM_CheckParm ("-lm_4")) - gl_lightmap_format = GL_RGBA; - if (*gl_lightmapmode.string) - { - switch(*gl_lightmapmode.string) - { - case '1': - gl_lightmap_format = GL_LUMINANCE; - break; - case 'a': - gl_lightmap_format = GL_ALPHA; - break; - case 'i': - gl_lightmap_format = GL_INTENSITY; - break; - case '3': - gl_lightmap_format = GL_RGB; - break; - case '4': - gl_lightmap_format = GL_RGBA; - break; - default: - Con_Printf("%s contains unrecognised type\n", gl_lightmapmode.name); - case '0': - break; - } - } -*/ - if (cl.worldmodel->fromgame == fg_quake3 && gl_lightmap_format != GL_RGB && gl_lightmap_format != GL_RGBA) - gl_lightmap_format = GL_RGB; - - - switch (gl_lightmap_format) - { - case GL_RGBA: - lightmap_bytes = 4; - break; - case GL_RGB: - lightmap_bytes = 3; - break; - case GL_LUMINANCE: - case GL_INTENSITY: - case GL_ALPHA: - lightmap_bytes = 1; - break; - } - - for (j=1 ; jname[0] == '*') - continue; - - r_pcurrentvertbase = m->vertexes; - currentmodel = m; - shift = GLR_LightmapShift(currentmodel); - - for (t = 0; t < m->numtextures; t++) - { - for (i=0 ; inumsurfaces ; i++) - {//extra texture loop so we get slightly less texture switches - if (m->surfaces[i].texinfo->texture == m->textures[t]) - { - GL_CreateSurfaceLightmap (m->surfaces + i, shift); - P_EmitSkyEffectTris(m, &m->surfaces[i]); - if (m->surfaces[i].mesh) //there are some surfaces that have a display list already (the subdivided ones) - continue; - GL_BuildSurfaceDisplayList (m->surfaces + i); - } - } - } - - GL_GenBrushModelVBO(m); - } - + int i; // // upload all lightmaps that were filled // @@ -3001,7 +295,7 @@ void GL_BuildLightmaps (void) qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes , LMBLOCK_WIDTH, LMBLOCK_HEIGHT, 0, - gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); + ((lightmap_bytes==3)?GL_RGB:GL_LUMINANCE), GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); if (gl_bump.ival) { diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index 6832bc1f..7715e7b4 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -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) { diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 29925695..c7bf0797 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -801,8 +801,8 @@ rendererinfo_t openglrendererinfo = { GLR_PushDlights, - GLR_AddStain, - GLR_LessenStains, + Surf_AddStain, + Surf_LessenStains, MediaGL_ShowFrameBGR_24_Flip, MediaGL_ShowFrameRGBA_32, diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 538b7728..3409bce6 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -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 diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index af9bc7a5..3945678f 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -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; diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index d99d5269..31ed5150 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -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; diff --git a/engine/gl/glmod_doom.c b/engine/gl/glmod_doom.c index 1eb25207..984bc4f9 100644 --- a/engine/gl/glmod_doom.c +++ b/engine/gl/glmod_doom.c @@ -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); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index e553d937..3c0fc10c 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -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); diff --git a/engine/gl/gltod3d/gl_fakegl.cpp b/engine/gl/gltod3d/gl_fakegl.cpp index 243c3d8a..70e707b6 100644 --- a/engine/gl/gltod3d/gl_fakegl.cpp +++ b/engine/gl/gltod3d/gl_fakegl.cpp @@ -4123,8 +4123,8 @@ rendererinfo_t d3drendererinfo = { GLR_PushDlights, - GLR_AddStain, - GLR_LessenStains, + Surf_AddStain, + Surf_LessenStains, MediaGL_ShowFrameBGR_24_Flip, MediaGL_ShowFrameRGBA_32, diff --git a/engine/gl/shader.h b/engine/gl/shader.h index a8f4d316..cccfac22 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -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 diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 6aa5031f..6ff1927e 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -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) { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index cf11c0ca..b8a06ebe 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -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; diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index d6f442ad..91dab6ec 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -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 diff --git a/engine/server/server.h b/engine/server/server.h index b183e4f8..bdd516d4 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -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]; diff --git a/engine/server/sv_demo.c b/engine/server/sv_demo.c index cb4dd507..b8bb9d41 100644 --- a/engine/server/sv_demo.c +++ b/engine/server/sv_demo.c @@ -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 diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 830440bb..34af88d3 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -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 ; norigin[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 ; jstate != 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) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index b00f5c05..f7ca23bd 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -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 ; inumsubmodels ; 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 ; inumsubmodels ; 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; inumsubmodels; 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 diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 203467cc..203e08a7 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -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(); diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 93d882d0..e46d7fe9 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -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]) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 66aeae73..51d28b7f 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -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_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); diff --git a/engine/server/world.c b/engine/server/world.c index 7d074f24..e448f052 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -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"); diff --git a/specs/qc_extensions.txt b/specs/qc_extensions.txt new file mode 100644 index 00000000..e164336f --- /dev/null +++ b/specs/qc_extensions.txt @@ -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;