diff --git a/Quake/cl_parse.c b/Quake/cl_parse.c index ca5d003b..c634cb8d 100644 --- a/Quake/cl_parse.c +++ b/Quake/cl_parse.c @@ -215,7 +215,7 @@ static int MSG_ReadSize16 (sizebuf_t *sb) { int solid = (((ssolid>>7) & 0x1F8) - 32+32768)<<16; /*up can be negative*/ solid|= ((ssolid & 0x1F)<<3); - solid|= ((ssolid & 0x3E0)<<10); + solid|= ((ssolid & 0x3E0)<<6); return solid; } } @@ -1426,10 +1426,6 @@ static void CL_ParseServerInfo (void) str = MSG_ReadString (); q_strlcpy (cl.levelname, str, sizeof(cl.levelname)); -// seperate the printfs so the server message can have a color - Con_Printf ("\n%s\n", Con_Quakebar(40)); //johnfitz - Con_Printf ("%c%s\n", 2, str); - //johnfitz -- tell user which protocol this is if (developer.value) { @@ -1474,6 +1470,10 @@ static void CL_ParseServerInfo (void) Con_Printf ("Using protocol %s", protname); Con_Printf ("\n"); + // seperate the printfs so the server message can have a color + Con_Printf ("\n%s\n", Con_Quakebar(40)); //johnfitz + Con_Printf ("%c%s\n", 2, str); + // first we go through and touch all of the precache data that still // happens to be in the cache, so precaching something else doesn't // needlessly purge it diff --git a/Quake/console.c b/Quake/console.c index c9b52bdb..5eb7f3d6 100644 --- a/Quake/console.c +++ b/Quake/console.c @@ -932,6 +932,7 @@ static const arg_completion_type_t arg_completion_types[] = { "map ", &extralevels }, { "changelevel ", &extralevels }, { "game ", &modlist }, + { "gamedir ", &modlist }, { "record ", &demolist }, { "playdemo ", &demolist }, { "timedemo ", &demolist } diff --git a/Quake/gl_rmain.c b/Quake/gl_rmain.c index 7b1fe92e..abb8381f 100644 --- a/Quake/gl_rmain.c +++ b/Quake/gl_rmain.c @@ -763,7 +763,7 @@ void R_ShowBoundingBoxes (void) int i; qcvm_t *oldvm; //in case we ever draw a scene from within csqc. - if (!r_showbboxes.value || cl.maxclients > 1 || !r_drawentities.value || !sv.active) + if (!r_showbboxes.value || cl.maxclients > 1 || !r_drawentities.value) return; glDisable (GL_DEPTH_TEST); @@ -773,38 +773,79 @@ void R_ShowBoundingBoxes (void) glDisable (GL_CULL_FACE); glColor3f (1,1,1); - oldvm = qcvm; - PR_SwitchQCVM(NULL); - PR_SwitchQCVM(&sv.qcvm); - for (i=1, ed=NEXT_EDICT(qcvm->edicts) ; inum_edicts ; i++, ed=NEXT_EDICT(ed)) + if (r_showbboxes.value == 2 || !sv.active) { - if (ed == sv_player || ed->free) - continue; //don't draw player's own bbox or freed edicts + entity_t *e; + for (i = 0; i < cl_numvisedicts; i++) + { //only the visible ents... + e = cl_visedicts[i]; -// if (r_showbboxes.value != 2) -// if (!SV_VisibleToClient (sv_player, ed, sv.worldmodel)) -// continue; //don't draw if not in pvs - - if (ed->v.mins[0] == ed->v.maxs[0] && ed->v.mins[1] == ed->v.maxs[1] && ed->v.mins[2] == ed->v.maxs[2]) - { - //point entity - R_EmitWirePoint (ed->v.origin); - } - else - { - //box entity - if ((ed->v.solid == SOLID_BSP || ed->v.solid == SOLID_EXT_BSPTRIGGER) && (ed->v.angles[0]||ed->v.angles[1]||ed->v.angles[2]) && pr_checkextension.value) - R_EmitWireBox (ed->v.absmin, ed->v.absmax); + if (e->eflags & EFLAGS_VIEWMODEL) + continue; //no point, probably outside the level. misleading. + if (e->netstate.solidsize == ES_SOLID_BSP && e->model) + { // explicit hulls in the BSP model. also accept non-bmodels too, probably bugs but their boxes will at least be approximate. + VectorAdd(e->origin, e->model->mins, mins); + VectorAdd(e->origin, e->model->maxs, maxs); + R_EmitWireBox (mins, maxs); + } + else if (e->netstate.solidsize == ES_SOLID_NOT) + { //we're actually using collision data here, so there'll be quite a few such ents unfortunately. we can just draw them as points, shouldn't be ambigous as points are normally nonsolid anyway. + if (e->model && e->model->type == mod_brush) + { //bmodels are just painful with their origin so far from their geometry (because origins are irrelevant). lie and show the middle of the geometry. should probably skip this if its a rotator. + VectorMA(e->origin, 0.5, e->model->mins, mins); + VectorMA(mins, 0.5, e->model->maxs, mins); + R_EmitWirePoint (mins); + } + else + R_EmitWirePoint (e->origin); + } else { - VectorAdd (ed->v.mins, ed->v.origin, mins); - VectorAdd (ed->v.maxs, ed->v.origin, maxs); + maxs[0] = maxs[1] = e->netstate.solidsize & 255; + mins[0] = mins[1] = -maxs[0]; + mins[2] = -(int)((e->netstate.solidsize >>8) & 255); + maxs[2] = (int)((e->netstate.solidsize>>16) & 65535) - 32768; + VectorAdd(e->origin, mins, mins); + VectorAdd(e->origin, maxs, maxs); R_EmitWireBox (mins, maxs); } } } - PR_SwitchQCVM(NULL); - PR_SwitchQCVM(oldvm); + else + { + oldvm = qcvm; + PR_SwitchQCVM(NULL); + PR_SwitchQCVM(&sv.qcvm); + for (i=1, ed=NEXT_EDICT(qcvm->edicts) ; inum_edicts ; i++, ed=NEXT_EDICT(ed)) + { + if (ed == sv_player || ed->free) + continue; //don't draw player's own bbox or freed edicts + + // if (r_showbboxes.value != 2) + // if (!SV_VisibleToClient (sv_player, ed, sv.worldmodel)) + // continue; //don't draw if not in pvs + + if (ed->v.mins[0] == ed->v.maxs[0] && ed->v.mins[1] == ed->v.maxs[1] && ed->v.mins[2] == ed->v.maxs[2]) + { + //point entity + R_EmitWirePoint (ed->v.origin); + } + else + { + //box entity + if ((ed->v.solid == SOLID_BSP || ed->v.solid == SOLID_EXT_BSPTRIGGER) && (ed->v.angles[0]||ed->v.angles[1]||ed->v.angles[2]) && pr_checkextension.value) + R_EmitWireBox (ed->v.absmin, ed->v.absmax); + else + { + VectorAdd (ed->v.mins, ed->v.origin, mins); + VectorAdd (ed->v.maxs, ed->v.origin, maxs); + R_EmitWireBox (mins, maxs); + } + } + } + PR_SwitchQCVM(NULL); + PR_SwitchQCVM(oldvm); + } glColor3f (1,1,1); glEnable (GL_TEXTURE_2D); diff --git a/Quake/gl_vidsdl.c b/Quake/gl_vidsdl.c index e027d6f0..ff7a0264 100644 --- a/Quake/gl_vidsdl.c +++ b/Quake/gl_vidsdl.c @@ -1591,7 +1591,9 @@ void VID_Init (void) int p, width, height, refreshrate, bpp; int display_width, display_height, display_refreshrate, display_bpp; qboolean fullscreen; - const char *read_vars[] = { "vid_fullscreen", + cvar_t *v; + size_t i; + static const char *read_vars[] = { "vid_fullscreen", "vid_width", "vid_height", "vid_refreshrate", @@ -1599,7 +1601,9 @@ void VID_Init (void) "vid_vsync", "vid_fsaa", "vid_desktopfullscreen", - "vid_borderless"}; + "vid_borderless", + "gl_load24bit", //including this here so we don't start up to the wrong setting. + }; #define num_readvars ( sizeof(read_vars)/sizeof(read_vars[0]) ) Cvar_RegisterVariable (&vid_fullscreen); //johnfitz @@ -1611,15 +1615,14 @@ void VID_Init (void) Cvar_RegisterVariable (&vid_fsaa); //QuakeSpasm Cvar_RegisterVariable (&vid_desktopfullscreen); //QuakeSpasm Cvar_RegisterVariable (&vid_borderless); //QuakeSpasm - Cvar_SetCallback (&vid_fullscreen, VID_Changed_f); - Cvar_SetCallback (&vid_width, VID_Changed_f); - Cvar_SetCallback (&vid_height, VID_Changed_f); - Cvar_SetCallback (&vid_refreshrate, VID_Changed_f); - Cvar_SetCallback (&vid_bpp, VID_Changed_f); - Cvar_SetCallback (&vid_vsync, VID_Changed_f); - Cvar_SetCallback (&vid_fsaa, VID_FSAA_f); - Cvar_SetCallback (&vid_desktopfullscreen, VID_Changed_f); - Cvar_SetCallback (&vid_borderless, VID_Changed_f); + for (i = 0; i < num_readvars; i++) + { + v = Cvar_FindVar(read_vars[i]); + if (!v || v->callback) + Sys_Error("Cvar %s not found yet, or already has a callback", read_vars[i]); + else + Cvar_SetCallback (v, VID_Changed_f); + } Cmd_AddCommand ("vid_unlock", VID_Unlock); //johnfitz Cmd_AddCommand ("vid_restart", VID_Restart); //johnfitz diff --git a/Quake/host_cmd.c b/Quake/host_cmd.c index 106311af..56425407 100644 --- a/Quake/host_cmd.c +++ b/Quake/host_cmd.c @@ -1434,11 +1434,11 @@ static void Host_Loadgame_f (void) { // parse an edict ent = EDICT_NUM(entnum); if (entnum < qcvm->num_edicts) { + SV_UnlinkEdict(ent); ent->free = false; memset (&ent->v, 0, qcvm->progs->entityfields * 4); } else { - SV_UnlinkEdict(ent); memset (ent, 0, qcvm->edict_size); ent->baseline = nullentitystate; } diff --git a/Quake/pl_linux.c b/Quake/pl_linux.c index 25fe6b4b..916d1d0d 100644 --- a/Quake/pl_linux.c +++ b/Quake/pl_linux.c @@ -91,5 +91,8 @@ char *PL_GetClipboardData (void) void PL_ErrorDialog (const char *errorMsg) { +#if SDL_MAJOR_VERSION >= 2 + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Sys_Error", errorMsg, NULL); +#endif } diff --git a/Quake/pr_edict.c b/Quake/pr_edict.c index d09ab750..e4a383d6 100644 --- a/Quake/pr_edict.c +++ b/Quake/pr_edict.c @@ -976,6 +976,8 @@ const char *ED_ParseEdict (const char *data, edict_t *ent) SV_Precache_Model(PR_GetString(ED_NewString(com_token))); else if (!strcmp(keyname, "_precache_sound") && sv.state == ss_loading) SV_Precache_Sound(PR_GetString(ED_NewString(com_token))); + else if (!strcmp(keyname, "_skyroom") && ent == sv.qcvm.edicts) + SV_SetupSkyRoom(com_token); } //spike continue; @@ -1194,6 +1196,7 @@ static void PR_MergeEngineFieldDefs (void) {"alpha", ev_float}, //just because we can (though its already handled in a weird hacky way) {"scale", ev_float}, //hurrah for being able to rescale entities. {"emiteffectnum", ev_float}, //constantly emitting particles, even without moving. + {"pvsflags", ev_float}, //extra controls to enable/disable pvs checks on ents. {"traileffectnum", ev_float}, //custom effect for trails //{"glow_size", ev_float}, //deprecated particle trail rubbish //{"glow_color", ev_float}, //deprecated particle trail rubbish diff --git a/Quake/progs.h b/Quake/progs.h index 02957158..523978bb 100644 --- a/Quake/progs.h +++ b/Quake/progs.h @@ -159,7 +159,7 @@ eval_t *GetEdictFieldValue(edict_t *ed, int fldofs); //handles invalid offsets w int ED_FindFieldOffset (const char *name); #define GetEdictFieldValid(fld) (qcvm->extfields.fld>=0) -#define GetEdictFieldEval(ed,fld) ((eval_t *)((char *)&ed->v + qcvm->extfields.fld*4)) //caller must validate the field first +#define GetEdictFieldEval(ed,fld) ((eval_t *)((float *)&ed->v + qcvm->extfields.fld)) //caller must validate the field first //from pr_cmds, no longer static so that pr_ext can use them. sizebuf_t *WriteDest (void); @@ -324,6 +324,7 @@ struct pr_extfields_s QCEXTFIELD(viewzoom, ".float") /*float*/ \ QCEXTFIELD(SendEntity, ".float(entity to, float changedflags)") /*function*/ \ QCEXTFIELD(SendFlags, ".float") /*float. :( */ \ + QCEXTFIELD(pvsflags, ".float") /*float*/ \ //end of list #define QCEXTFIELD(n,t) int n; diff --git a/Quake/r_world.c b/Quake/r_world.c index 61c9d1bf..393e6396 100644 --- a/Quake/r_world.c +++ b/Quake/r_world.c @@ -643,8 +643,7 @@ static void GLWater_CreateShaders (void) //The following 4 lines SHOULD match the software renderer, except normalised coords rather than snapped texels "#define M_PI 3.14159\n" "#define TIMEBIAS (((WarpTime*20.0)*M_PI*2.0)/128.0)\n" - " ntc.s += 0.125 + sin(tc_tex.t*M_PI + TIMEBIAS)*0.125;\n" - " ntc.t += 0.125 + sin(tc_tex.s*M_PI + TIMEBIAS)*0.125;\n" + " ntc += 0.125 + sin(tc_tex.ts*M_PI + TIMEBIAS)*0.125;\n" " vec4 result = texture2D(Tex, ntc.st);\n" "#ifdef LIT\n" " result *= texture2D(LMTex, tc_lm.xy);\n" diff --git a/Quake/server.h b/Quake/server.h index 6e547832..d1000767 100644 --- a/Quake/server.h +++ b/Quake/server.h @@ -99,6 +99,9 @@ typedef struct eval_t *ptr; } customstats[MAX_CL_STATS*2]; //strings or numeric... size_t numcustomstats; + + qboolean skyroom_pos_known; + vec4_t skyroom_pos; } server_t; @@ -289,6 +292,13 @@ typedef struct client_s #define MSG_EXT_MULTICAST 4 // temporary buffer that can be splurged more reliably / with more control. #define MSG_EXT_ENTITY 5 // for csqc networking. we don't actually support this. I'm just defining it for completeness. +#define PVSF_NORMALPVS 0x0 +#define PVSF_NOTRACECHECK 0x1 +#define PVSF_USEPHS 0x2 +#define PVSF_IGNOREPVS 0x3 +#define PVSF_MODE_MASK 0x3 +#define PVSF_NOREMOVE 0x80 + //============================================================================ extern cvar_t teamplay; @@ -349,5 +359,7 @@ void SV_RunClients (void); void SV_SaveSpawnparms (); void SV_SpawnServer (const char *server); +void SV_SetupSkyRoom(char *value); + #endif /* _QUAKE_SERVER_H */ diff --git a/Quake/sv_main.c b/Quake/sv_main.c index 39a02f0b..fae15d63 100644 --- a/Quake/sv_main.c +++ b/Quake/sv_main.c @@ -1186,6 +1186,7 @@ void SV_BuildEntityState(client_t *client, edict_t *ent, entity_state_t *state) } byte *SV_FatPVS (vec3_t org, qmodel_t *worldmodel); +static void SV_AddToFatPVS (vec3_t org, mnode_t *node, qmodel_t *worldmodel); static void SVFTE_BuildSnapshotForClient (client_t *client) { unsigned int e, i; @@ -1208,6 +1209,11 @@ static void SVFTE_BuildSnapshotForClient (client_t *client) // find the client's PVS VectorAdd (clent->v.origin, clent->v.view_ofs, org); pvs = SV_FatPVS (org, qcvm->worldmodel); + if (sv.skyroom_pos_known) + { + VectorMA(sv.skyroom_pos, sv.skyroom_pos[3], org, org); + SV_AddToFatPVS (org, qcvm->worldmodel->nodes, qcvm->worldmodel); //spike -- allow _skyroom term to punch a hole through the server's pvs. FIXME: no paralax considered here. + } if (maxentities > (unsigned int)qcvm->num_edicts) maxentities = (unsigned int)qcvm->num_edicts; @@ -1237,7 +1243,7 @@ static void SVFTE_BuildSnapshotForClient (client_t *client) } eflags = 0; - emiteffect = GetEdictFieldValue(ent, qcvm->extfields.emiteffectnum)->_float; + emiteffect = GetEdictFieldEval(ent, emiteffectnum)->_float; iscsqc = cancsqc && GetEdictFieldEval(ent, SendEntity)->function; if (ent != clent) // clent is ALLWAYS sent { @@ -1245,7 +1251,7 @@ static void SVFTE_BuildSnapshotForClient (client_t *client) if ((!ent->v.modelindex || !PR_GetString(ent->v.model)[0]) && !emiteffect && !iscsqc) { invisible: - if (client->pendingcsqcentities_bits[e] /*&& !((int)GetEdictFieldEval(ent, pvsflags)->_float & PVFS_NOREMOVE)*/) + if (client->pendingcsqcentities_bits[e] && !((int)GetEdictFieldEval(ent, pvsflags)->_float & PVSF_NOREMOVE)) client->pendingcsqcentities_bits[e] |= SENDFLAG_REMOVE; continue; } @@ -1255,28 +1261,27 @@ invisible: eflags |= EFLAGS_VIEWMODEL; else if (val && val->edict) goto invisible; - else + else switch((int)GetEdictFieldEval(ent, pvsflags)->_float&PVSF_MODE_MASK) { + case PVSF_NOTRACECHECK: //we don't do trace checks anyway, oh well. + case PVSF_NORMALPVS: //attached entities should use the pvs of the parent rather than the child (because the child will typically be bugging out around '0 0 0', so won't be useful) parent = ent; - while ((val = GetEdictFieldValue(parent, qcvm->extfields.tag_entity)) && val->edict) - parent = PROG_TO_EDICT(val->edict); - if (parent->num_leafs) + while (GetEdictFieldEval(parent, tag_entity)->edict) + parent = PROG_TO_EDICT(GetEdictFieldEval(parent, tag_entity)->edict); + if (parent->num_leafs < MAX_ENT_LEAFS) //assumed to be in all leafs, if there's an overflow. { // ignore if not touching a PV leaf for (i=0 ; i < parent->num_leafs ; i++) if (pvs[parent->leafnums[i] >> 3] & (1 << (parent->leafnums[i]&7) )) break; - - // ericw -- added ent->num_leafs < MAX_ENT_LEAFS condition. - // - // if ent->num_leafs == MAX_ENT_LEAFS, the ent is visible from too many leafs - // for us to say whether it's in the PVS, so don't try to vis cull it. - // this commonly happens with rotators, because they often have huge bboxes - // spanning the entire map, or really tall lifts, etc. - if (i == parent->num_leafs && parent->num_leafs < MAX_ENT_LEAFS) + if (i == parent->num_leafs) goto invisible; // not visible } + break; + case PVSF_USEPHS: //we don't support PHS. expand it wider than asked + case PVSF_IGNOREPVS: + break; } } @@ -2111,8 +2116,8 @@ retry: MSG_WriteByte (&client->message, svc_setview); MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict)); - MSG_WriteByte (&host_client->message, svc_signonnum); - MSG_WriteByte (&host_client->message, 1); + MSG_WriteByte (&client->message, svc_signonnum); + MSG_WriteByte (&client->message, 1); client->sendsignon = PRESPAWN_FLUSH; @@ -2367,7 +2372,24 @@ static int fatbytes; static byte *fatpvs; static int fatpvs_capacity; -void SV_AddToFatPVS (vec3_t org, mnode_t *node, qmodel_t *worldmodel) //johnfitz -- added worldmodel as a parameter + +void SV_SetupSkyRoom(char *value) +{ + sv.skyroom_pos_known = true; + + sv.skyroom_pos[0] = strtod(value, &value); while(*value == ' ' || *value == '\t') value++; + sv.skyroom_pos[1] = strtod(value, &value); while(*value == ' ' || *value == '\t') value++; + sv.skyroom_pos[2] = strtod(value, &value); while(*value == ' ' || *value == '\t') value++; + sv.skyroom_pos[3] = strtod(value, &value); while(*value == ' ' || *value == '\t') value++; + +// sv.skyroom_orientation[3] = strtod(value, &value); while(*value == ' ' || *value == '\t') value++; +// sv.skyroom_orientation[0] = strtod(value, &value); while(*value == ' ' || *value == '\t') value++; +// sv.skyroom_orientation[1] = strtod(value, &value); while(*value == ' ' || *value == '\t') value++; +// sv.skyroom_orientation[2] = strtod(value, &value); while(*value == ' ' || *value == '\t') value++; +} + + +static void SV_AddToFatPVS (vec3_t org, mnode_t *node, qmodel_t *worldmodel) //johnfitz -- added worldmodel as a parameter { int i; byte *pvs; @@ -2481,6 +2503,11 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg) // find the client's PVS VectorAdd (clent->v.origin, clent->v.view_ofs, org); pvs = SV_FatPVS (org, qcvm->worldmodel); + if (sv.skyroom_pos_known) + { + VectorMA(sv.skyroom_pos, sv.skyroom_pos[3], org, org); + SV_AddToFatPVS (org, qcvm->worldmodel->nodes, qcvm->worldmodel); //spike -- allow _skyroom term to punch a hole through the server's pvs. FIXME: no paralax considered here. + } // send over all entities (excpet the client) that touch the pvs ent = NEXT_EDICT(qcvm->edicts); diff --git a/Quake/world.c b/Quake/world.c index fee171d2..88dc963b 100644 --- a/Quake/world.c +++ b/Quake/world.c @@ -148,7 +148,8 @@ hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset) if (!model || model->type != mod_brush) { - Con_Warning ("SOLID_BSP with a non bsp model (%s at %f %f %f)\n", + Con_Warning ("SOLID_BSP%s with a non bsp model (%s at %f %f %f)\n", + (ent->v.solid == SOLID_EXT_BSPTRIGGER)?"TRIGGER":"", PR_GetString(ent->v.classname), ent->v.origin[0], ent->v.origin[1], ent->v.origin[2]); goto nohitmeshsupport; }