X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=cl_main.c;h=4d209bcd5821edad70a2ead14884e62f18c6f078;hp=5e287a8fadd067607682edc4ccb7f59af707239b;hb=c369fcf631b61d72c598ae37b01fc89a318044ae;hpb=7d184704e499b001046ef76851ed70d53f93d38a diff --git a/cl_main.c b/cl_main.c index 5e287a8f..4d209bcd 100644 --- a/cl_main.c +++ b/cl_main.c @@ -53,6 +53,8 @@ cvar_t r_draweffects = {0, "r_draweffects", "1"}; cvar_t cl_explosions = {CVAR_SAVE, "cl_explosions", "1"}; cvar_t cl_stainmaps = {CVAR_SAVE, "cl_stainmaps", "1"}; +cvar_t cl_beampolygons = {CVAR_SAVE, "cl_beampolygons", "1"}; + mempool_t *cl_scores_mempool; mempool_t *cl_refdef_mempool; mempool_t *cl_entities_mempool; @@ -259,6 +261,37 @@ static void CL_PrintEntities_f (void) } } +static const vec3_t nomodelmins = {-16, -16, -16}; +static const vec3_t nomodelmaxs = {16, 16, 16}; +void CL_BoundingBoxForEntity(entity_render_t *ent) +{ + if (ent->model) + { + if (ent->angles[0] || ent->angles[2]) + { + // pitch or roll + VectorAdd(ent->origin, ent->model->rotatedmins, ent->mins); + VectorAdd(ent->origin, ent->model->rotatedmaxs, ent->maxs); + } + else if (ent->angles[1]) + { + // yaw + VectorAdd(ent->origin, ent->model->yawmins, ent->mins); + VectorAdd(ent->origin, ent->model->yawmaxs, ent->maxs); + } + else + { + VectorAdd(ent->origin, ent->model->normalmins, ent->mins); + VectorAdd(ent->origin, ent->model->normalmaxs, ent->maxs); + } + } + else + { + VectorAdd(ent->origin, nomodelmins, ent->mins); + VectorAdd(ent->origin, nomodelmaxs, ent->maxs); + } +} + void CL_LerpUpdate(entity_t *e) { entity_persistent_t *p; @@ -330,6 +363,103 @@ static float CL_LerpPoint (void) return bound(0, f, 1); } +void CL_ClearTempEntities (void) +{ + cl_num_temp_entities = 0; +} + +entity_t *CL_NewTempEntity (void) +{ + entity_t *ent; + + if (r_refdef.numentities >= r_refdef.maxentities) + return NULL; + if (cl_num_temp_entities >= cl_max_temp_entities) + return NULL; + ent = &cl_temp_entities[cl_num_temp_entities++]; + memset (ent, 0, sizeof(*ent)); + r_refdef.entities[r_refdef.numentities++] = &ent->render; + + ent->render.colormap = -1; // no special coloring + ent->render.scale = 1; + ent->render.alpha = 1; + return ent; +} + +void CL_AllocDlight (entity_render_t *ent, vec3_t org, float radius, float red, float green, float blue, float decay, float lifetime) +{ + int i; + dlight_t *dl; + + /* +// first look for an exact key match + if (ent) + { + dl = cl_dlights; + for (i = 0;i < MAX_DLIGHTS;i++, dl++) + if (dl->ent == ent) + goto dlightsetup; + } + */ + +// then look for anything else + dl = cl_dlights; + for (i = 0;i < MAX_DLIGHTS;i++, dl++) + if (!dl->radius) + goto dlightsetup; + + // unable to find one + return; + +dlightsetup: + //Con_Printf("dlight %i : %f %f %f : %f %f %f\n", i, org[0], org[1], org[2], red * radius, green * radius, blue * radius); + memset (dl, 0, sizeof(*dl)); + dl->ent = ent; + VectorCopy(org, dl->origin); + dl->radius = radius; + dl->color[0] = red; + dl->color[1] = green; + dl->color[2] = blue; + dl->decay = decay; + if (lifetime) + dl->die = cl.time + lifetime; + else + dl->die = 0; +} + +void CL_DecayLights (void) +{ + int i; + dlight_t *dl; + float time; + + time = cl.time - cl.oldtime; + + dl = cl_dlights; + for (i=0 ; iradius) + continue; + if (dl->die < cl.time) + { + dl->radius = 0; + continue; + } + + dl->radius -= time*dl->decay; + if (dl->radius < 0) + dl->radius = 0; + } +} + +void CL_RelinkWorld (void) +{ + if (cl_num_entities < 1) + cl_num_entities = 1; + cl_brushmodel_entities[cl_num_brushmodel_entities++] = &cl_entities[0].render; + CL_BoundingBoxForEntity(&cl_entities[0].render); +} + static void CL_RelinkStaticEntities(void) { int i; @@ -345,11 +475,12 @@ static void CL_RelinkStaticEntities(void) CL_RelinkEntities =============== */ -static void CL_RelinkNetworkEntities() +extern qboolean Nehahrademcompatibility; +static void CL_RelinkNetworkEntities(void) { entity_t *ent; int i, effects, temp; - float d, bobjrotate, bobjoffset, dlightradius, lerp; + float d, bobjrotate, bobjoffset, lerp; vec3_t oldorg, neworg, delta, dlightcolor, v, v2, mins, maxs; bobjrotate = ANGLEMOD(100*cl.time); @@ -413,11 +544,13 @@ static void CL_RelinkNetworkEntities() VectorCopy (neworg, ent->persistent.trail_origin); // persistent.modelindex will be updated by CL_LerpUpdate - if (ent->state_current.modelindex != ent->persistent.modelindex) + if (ent->state_current.modelindex != ent->persistent.modelindex || !ent->state_previous.active) VectorCopy(neworg, oldorg); VectorCopy (neworg, ent->render.origin); ent->render.flags = ent->state_current.flags; + if (i == cl.viewentity) + ent->render.flags |= RENDER_EXTERIORMODEL; ent->render.effects = effects = ent->state_current.effects; if (ent->state_current.flags & RENDER_COLORMAPPED) ent->render.colormap = ent->state_current.colormap; @@ -433,7 +566,6 @@ static void CL_RelinkNetworkEntities() CL_LerpUpdate(ent); // handle effects now... - dlightradius = 0; dlightcolor[0] = 0; dlightcolor[1] = 0; dlightcolor[2] = 0; @@ -442,7 +574,19 @@ static void CL_RelinkNetworkEntities() if (effects) { if (effects & EF_BRIGHTFIELD) - CL_EntityParticles (ent); + { + if (gamemode == GAME_NEXIUZ) + { + dlightcolor[0] += 100.0f; + dlightcolor[1] += 200.0f; + dlightcolor[2] += 400.0f; + // don't do trail if we have no previous location + if (ent->state_previous.active) + CL_RocketTrail (oldorg, neworg, 8, ent); + } + else + CL_EntityParticles (ent); + } if (effects & EF_MUZZLEFLASH) ent->persistent.muzzleflash = 100.0f; if (effects & EF_DIMLIGHT) @@ -517,7 +661,7 @@ static void CL_RelinkNetworkEntities() v2[0] = v[0] * 18 + neworg[0]; v2[1] = v[1] * 18 + neworg[1]; v2[2] = v[2] * 18 + neworg[2] + 16; - CL_TraceLine(neworg, v2, v, NULL, 0, true); + CL_TraceLine(neworg, v2, v, NULL, 0, true, NULL); CL_AllocDlight (NULL, v, ent->persistent.muzzleflash, 1, 1, 1, 0, 0); ent->persistent.muzzleflash -= cl.frametime * 1000; @@ -580,7 +724,7 @@ static void CL_RelinkNetworkEntities() { // * 4 for the expansion from 0-255 to 0-1023 range, // / 255 to scale down byte colors - VectorMA(dlightcolor, ent->state_current.glowsize * (4.0f / 255.0f), (qbyte *)&d_8to24table[ent->state_current.glowcolor], dlightcolor); + VectorMA(dlightcolor, ent->state_current.glowsize * (4.0f / 255.0f), (qbyte *)&palette_complete[ent->state_current.glowcolor], dlightcolor); } // LordHavoc: customizable trail if (ent->render.flags & RENDER_GLOWTRAIL) @@ -590,90 +734,43 @@ static void CL_RelinkNetworkEntities() { VectorCopy(neworg, v); // hack to make glowing player light shine on their gun - if (i == cl.viewentity && !chase_active.integer) + if (i == cl.viewentity/* && !chase_active.integer*/) v[2] += 30; - CL_AllocDlight (NULL, v, 1, dlightcolor[0], dlightcolor[1], dlightcolor[2], 0, 0); + CL_AllocDlight (&ent->render, v, 1, dlightcolor[0], dlightcolor[1], dlightcolor[2], 0, 0); } - if (chase_active.integer) - { - if (ent->render.flags & RENDER_VIEWMODEL) - continue; - } - else - { - if (i == cl.viewentity || (ent->render.flags & RENDER_EXTERIORMODEL)) - continue; - } + if (chase_active.integer && (ent->render.flags & RENDER_VIEWMODEL)) + continue; - if (ent->render.model == NULL) + // don't show entities with no modelindex (note: this still shows + // entities which have a modelindex that resolved to a NULL model) + if (!ent->state_current.modelindex) continue; if (effects & EF_NODRAW) continue; - if (ent->render.angles[0] || ent->render.angles[2]) - { - // pitch or roll - VectorAdd(ent->render.origin, ent->render.model->rotatedmins, ent->render.mins); - VectorAdd(ent->render.origin, ent->render.model->rotatedmaxs, ent->render.maxs); - } - else if (ent->render.angles[1]) - { - // yaw - VectorAdd(ent->render.origin, ent->render.model->yawmins, ent->render.mins); - VectorAdd(ent->render.origin, ent->render.model->yawmaxs, ent->render.maxs); - } - else - { - VectorAdd(ent->render.origin, ent->render.model->normalmins, ent->render.mins); - VectorAdd(ent->render.origin, ent->render.model->normalmaxs, ent->render.maxs); - } + CL_BoundingBoxForEntity(&ent->render); + if (ent->render.model && ent->render.model->name[0] == '*' && ent->render.model->type == mod_brush) + cl_brushmodel_entities[cl_num_brushmodel_entities++] = &ent->render; + + // note: the cl.viewentity and intermission check is to hide player + // shadow during intermission and during the Nehahra movie and + // Nehahra cinematics + if (!(ent->state_current.effects & EF_NOSHADOW) + && !(ent->state_current.effects & EF_ADDITIVE) + && (ent->state_current.alpha == 255) + && !(ent->render.flags & RENDER_VIEWMODEL) + && (i != cl.viewentity || (!cl.intermission && !Nehahrademcompatibility))) + ent->render.flags |= RENDER_SHADOW; if (r_refdef.numentities < r_refdef.maxentities) r_refdef.entities[r_refdef.numentities++] = &ent->render; - if (ent->render.model->name[0] == '*' && ent->render.model->type == mod_brush) - cl_brushmodel_entities[cl_num_brushmodel_entities++] = &ent->render; - if (cl_num_entities < i + 1) cl_num_entities = i + 1; } } -void CL_LerpPlayer(float frac) -{ - int i; - float d; - - if (cl.entitydatabase.numframes && cl.viewentity == cl.playerentity) - { - cl.viewentorigin[0] = cl.viewentoriginold[0] + frac * (cl.viewentoriginnew[0] - cl.viewentoriginold[0]); - cl.viewentorigin[1] = cl.viewentoriginold[1] + frac * (cl.viewentoriginnew[1] - cl.viewentoriginold[1]); - cl.viewentorigin[2] = cl.viewentoriginold[2] + frac * (cl.viewentoriginnew[2] - cl.viewentoriginold[2]); - } - else - VectorCopy (cl_entities[cl.viewentity].render.origin, cl.viewentorigin); - - cl.viewzoom = cl.viewzoomold + frac * (cl.viewzoomnew - cl.viewzoomold); - - for (i = 0;i < 3;i++) - cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); - - if (cls.demoplayback) - { - // interpolate the angles - for (i = 0;i < 3;i++) - { - d = cl.mviewangles[0][i] - cl.mviewangles[1][i]; - if (d > 180) - d -= 360; - else if (d < -180) - d += 360; - cl.viewangles[i] = cl.mviewangles[1][i] + frac * d; - } - } -} - void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate) { int i; @@ -699,7 +796,7 @@ void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float } } -static void CL_RelinkEffects() +static void CL_RelinkEffects(void) { int i, intframe; cl_effect_t *e; @@ -747,33 +844,319 @@ static void CL_RelinkEffects() ent->render.scale = 1; ent->render.alpha = 1; - if (ent->render.angles[0] || ent->render.angles[2]) - { - // pitch or roll - VectorAdd(ent->render.origin, ent->render.model->rotatedmins, ent->render.mins); - VectorAdd(ent->render.origin, ent->render.model->rotatedmaxs, ent->render.maxs); - } - else if (ent->render.angles[1]) - { - // yaw - VectorAdd(ent->render.origin, ent->render.model->yawmins, ent->render.mins); - VectorAdd(ent->render.origin, ent->render.model->yawmaxs, ent->render.maxs); - } - else - { - VectorAdd(ent->render.origin, ent->render.model->normalmins, ent->render.mins); - VectorAdd(ent->render.origin, ent->render.model->normalmaxs, ent->render.maxs); - } + CL_BoundingBoxForEntity(&ent->render); } } } } -void CL_RelinkWorld (void) +void CL_RelinkBeams (void) { - if (cl_num_entities < 1) - cl_num_entities = 1; - cl_brushmodel_entities[cl_num_brushmodel_entities++] = &cl_entities[0].render; + int i; + beam_t *b; + vec3_t dist, org; + float d; + entity_t *ent; + float yaw, pitch; + float forward; + + for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++) + { + if (!b->model || b->endtime < cl.time) + continue; + + // if coming from the player, update the start position + //if (b->entity == cl.viewentity) + // VectorCopy (cl_entities[cl.viewentity].render.origin, b->start); + if (b->entity && cl_entities[b->entity].state_current.active) + { + VectorCopy (cl_entities[b->entity].render.origin, b->start); + b->start[2] += 16; + } + + if (cl_beampolygons.integer) + continue; + + // calculate pitch and yaw + VectorSubtract (b->end, b->start, dist); + + if (dist[1] == 0 && dist[0] == 0) + { + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); + pitch = (int) (atan2(dist[2], forward) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + // add new entities for the lightning + VectorCopy (b->start, org); + d = VectorNormalizeLength(dist); + while (d > 0) + { + ent = CL_NewTempEntity (); + if (!ent) + return; + VectorCopy (org, ent->render.origin); + ent->render.model = b->model; + ent->render.effects = EF_FULLBRIGHT; + ent->render.angles[0] = pitch; + ent->render.angles[1] = yaw; + ent->render.angles[2] = rand()%360; + CL_BoundingBoxForEntity(&ent->render); + VectorMA(org, 30, dist, org); + d -= 30; + } + } +} + +cvar_t r_lightningbeam_thickness = {CVAR_SAVE, "r_lightningbeam_thickness", "4"}; +cvar_t r_lightningbeam_scroll = {CVAR_SAVE, "r_lightningbeam_scroll", "5"}; +cvar_t r_lightningbeam_repeatdistance = {CVAR_SAVE, "r_lightningbeam_repeatdistance", "1024"}; +cvar_t r_lightningbeam_color_red = {CVAR_SAVE, "r_lightningbeam_color_red", "1"}; +cvar_t r_lightningbeam_color_green = {CVAR_SAVE, "r_lightningbeam_color_green", "1"}; +cvar_t r_lightningbeam_color_blue = {CVAR_SAVE, "r_lightningbeam_color_blue", "1"}; + +rtexture_t *r_lightningbeamtexture; +rtexturepool_t *r_lightningbeamtexturepool; + +int r_lightningbeamelements[18] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11}; + +void r_lightningbeams_start(void) +{ + float r, g, b, intensity, fx, width, center; + int x, y; + qbyte *data, *noise1, *noise2; + data = Mem_Alloc(tempmempool, 32 * 512 * 4); + noise1 = Mem_Alloc(tempmempool, 512 * 512); + noise2 = Mem_Alloc(tempmempool, 512 * 512); + fractalnoise(noise1, 512, 8); + fractalnoise(noise2, 512, 16); + + for (y = 0;y < 512;y++) + { + width = noise1[y * 512] * (1.0f / 256.0f) * 3.0f + 3.0f; + center = (noise1[y * 512 + 64] / 256.0f) * (32.0f - (width + 1.0f) * 2.0f) + (width + 1.0f); + for (x = 0;x < 32;x++, fx++) + { + fx = (x - center) / width; + intensity = (1.0f - fx * fx) * (noise2[y*512+x] * (1.0f / 256.0f) * 0.33f + 0.66f); + intensity = bound(0, intensity, 1); + r = intensity * 2.0f - 1.0f; + g = intensity * 3.0f - 1.0f; + b = intensity * 3.0f; + data[(y * 32 + x) * 4 + 0] = (qbyte)(bound(0, r, 1) * 255.0f); + data[(y * 32 + x) * 4 + 1] = (qbyte)(bound(0, g, 1) * 255.0f); + data[(y * 32 + x) * 4 + 2] = (qbyte)(bound(0, b, 1) * 255.0f); + data[(y * 32 + x) * 4 + 3] = (qbyte)255; + } + } + + r_lightningbeamtexturepool = R_AllocTexturePool(); + r_lightningbeamtexture = R_LoadTexture2D(r_lightningbeamtexturepool, "lightningbeam", 32, 512, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); + Mem_Free(noise1); + Mem_Free(noise2); + Mem_Free(data); +} + +void r_lightningbeams_shutdown(void) +{ + r_lightningbeamtexture = NULL; + R_FreeTexturePool(&r_lightningbeamtexturepool); +} + +void r_lightningbeams_newmap(void) +{ +} + +void R_LightningBeams_Init(void) +{ + Cvar_RegisterVariable(&r_lightningbeam_thickness); + Cvar_RegisterVariable(&r_lightningbeam_scroll); + Cvar_RegisterVariable(&r_lightningbeam_repeatdistance); + Cvar_RegisterVariable(&r_lightningbeam_color_red); + Cvar_RegisterVariable(&r_lightningbeam_color_green); + Cvar_RegisterVariable(&r_lightningbeam_color_blue); + R_RegisterModule("R_LightningBeams", r_lightningbeams_start, r_lightningbeams_shutdown, r_lightningbeams_newmap); +} + +void R_CalcLightningBeamPolygonVertices(float *v, float *tc, const float *start, const float *end, const float *offset, float t1, float t2) +{ + // near right corner + VectorAdd (start, offset, (v + 0));tc[ 0] = 0;tc[ 1] = t1; + // near left corner + VectorSubtract(start, offset, (v + 4));tc[ 4] = 1;tc[ 5] = t1; + // far left corner + VectorSubtract(end , offset, (v + 8));tc[ 8] = 1;tc[ 9] = t2; + // far right corner + VectorAdd (end , offset, (v + 12));tc[12] = 0;tc[13] = t2; +} + +void R_FogLightningBeamColors(const float *v, float *c, int numverts, float r, float g, float b, float a) +{ + int i; + vec3_t fogvec; + float ifog; + for (i = 0;i < numverts;i++, v += 4, c += 4) + { + VectorSubtract(v, r_origin, fogvec); + ifog = 1 - exp(fogdensity/DotProduct(fogvec,fogvec)); + c[0] = r * ifog; + c[1] = g * ifog; + c[2] = b * ifog; + c[3] = a; + } +} + +float beamrepeatscale; + +void R_DrawLightningBeamCallback(const void *calldata1, int calldata2) +{ + const beam_t *b = calldata1; + rmeshstate_t m; + vec3_t beamdir, right, up, offset; + float length, t1, t2; + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_SRC_ALPHA; + m.blendfunc2 = GL_ONE; + m.tex[0] = R_GetTexture(r_lightningbeamtexture); + R_Mesh_State(&m); + R_Mesh_Matrix(&r_identitymatrix); + + // calculate beam direction (beamdir) vector and beam length + // get difference vector + VectorSubtract(b->end, b->start, beamdir); + // find length of difference vector + length = sqrt(DotProduct(beamdir, beamdir)); + // calculate scale to make beamdir a unit vector (normalized) + t1 = 1.0f / length; + // scale beamdir so it is now normalized + VectorScale(beamdir, t1, beamdir); + + // calculate up vector such that it points toward viewer, and rotates around the beamdir + // get direction from start of beam to viewer + VectorSubtract(r_origin, b->start, up); + // remove the portion of the vector that moves along the beam + // (this leaves only a vector pointing directly away from the beam) + t1 = -DotProduct(up, beamdir); + VectorMA(up, t1, beamdir, up); + // now we have a vector pointing away from the beam, now we need to normalize it + VectorNormalizeFast(up); + // generate right vector from forward and up, the result is already normalized + // (CrossProduct returns a vector of multiplied length of the two inputs) + CrossProduct(beamdir, up, right); + + // calculate T coordinate scrolling (start and end texcoord along the beam) + t1 = cl.time * -r_lightningbeam_scroll.value; + t1 = t1 - (int) t1; + t2 = t1 + beamrepeatscale * length; + + // the beam is 3 polygons in this configuration: + // 3 2 + // * * + // 1****** + // * * + // * * + // they are showing different portions of the beam texture, creating an + // illusion of a beam that appears to curl around in 3D space + // (and realize that the whole polygon assembly orients itself to face + // the viewer) + + // polygon 1, verts 0-3 + VectorScale(right, r_lightningbeam_thickness.value, offset); + R_CalcLightningBeamPolygonVertices(varray_vertex, varray_texcoord[0], b->start, b->end, offset, t1, t2); + + // polygon 2, verts 4-7 + VectorAdd(right, up, offset); + VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset); + R_CalcLightningBeamPolygonVertices(varray_vertex + 16, varray_texcoord[0] + 16, b->start, b->end, offset, t1 + 0.33, t2 + 0.33); + + // polygon 3, verts 8-11 + VectorSubtract(right, up, offset); + VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset); + R_CalcLightningBeamPolygonVertices(varray_vertex + 32, varray_texcoord[0] + 32, b->start, b->end, offset, t1 + 0.66, t2 + 0.66); + + if (fogenabled) + { + // per vertex colors if fog is used + GL_UseColorArray(); + R_FogLightningBeamColors(varray_vertex, varray_color, 12, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1); + } + else + { + // solid color if fog is not used + GL_Color(r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1); + } + + // draw the 3 polygons as one batch of 6 triangles using the 12 vertices + R_Mesh_Draw(12, 6, r_lightningbeamelements); +} + +void R_DrawLightningBeams (void) +{ + int i; + beam_t *b; + vec3_t org; + + if (!cl_beampolygons.integer) + return; + + beamrepeatscale = 1.0f / r_lightningbeam_repeatdistance.value; + for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++) + { + if (b->model && b->endtime >= cl.time) + { + VectorAdd(b->start, b->end, org); + VectorScale(org, 0.5f, org); + R_MeshQueue_AddTransparent(org, R_DrawLightningBeamCallback, b, 0); + } + } +} + + +void CL_LerpPlayer(float frac) +{ + int i; + float d; + + if (cl.entitydatabase.numframes && cl.viewentity == cl.playerentity) + { + cl.viewentorigin[0] = cl.viewentoriginold[0] + frac * (cl.viewentoriginnew[0] - cl.viewentoriginold[0]); + cl.viewentorigin[1] = cl.viewentoriginold[1] + frac * (cl.viewentoriginnew[1] - cl.viewentoriginold[1]); + cl.viewentorigin[2] = cl.viewentoriginold[2] + frac * (cl.viewentoriginnew[2] - cl.viewentoriginold[2]); + } + else + VectorCopy (cl_entities[cl.viewentity].render.origin, cl.viewentorigin); + + cl.viewzoom = cl.viewzoomold + frac * (cl.viewzoomnew - cl.viewzoomold); + + for (i = 0;i < 3;i++) + cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); + + if (cls.demoplayback) + { + // interpolate the angles + for (i = 0;i < 3;i++) + { + d = cl.mviewangles[0][i] - cl.mviewangles[1][i]; + if (d > 180) + d -= 360; + else if (d < -180) + d += 360; + cl.viewangles[i] = cl.mviewangles[1][i] + frac * d; + } + } } void CL_RelinkEntities (void) @@ -786,10 +1169,10 @@ void CL_RelinkEntities (void) CL_ClearTempEntities(); CL_DecayLights(); CL_RelinkWorld(); - CL_RelinkBeams(); CL_RelinkStaticEntities(); CL_RelinkNetworkEntities(); CL_RelinkEffects(); + CL_RelinkBeams(); CL_MoveParticles(); CL_LerpPlayer(frac); @@ -835,7 +1218,7 @@ int CL_ReadFromServer (void) cl_num_entities = 0; cl_num_brushmodel_entities = 0; - if (cls.state == ca_connected && cl.worldmodel) + if (cls.state == ca_connected && cls.signon == SIGNONS) { CL_RelinkEntities (); @@ -877,7 +1260,7 @@ void CL_SendCmd (void) CL_SendMove (&cmd); } #ifndef NOROUTINGFIX - else + else if (cls.signon == 0 && !cls.demoplayback) { // LordHavoc: fix for NAT routing of netquake: // bounce back a clc_nop message to the newly allocated server port, @@ -885,9 +1268,21 @@ void CL_SendCmd (void) // the server waits for this before sending anything if (realtime > cl.sendnoptime) { - Con_DPrintf("sending clc_nop to get server's attention\n"); cl.sendnoptime = realtime + 3; - MSG_WriteByte(&cls.message, clc_nop); + Con_DPrintf("sending clc_nop to get server's attention\n"); + { + sizebuf_t buf; + qbyte data[128]; + buf.maxsize = 128; + buf.cursize = 0; + buf.data = data; + MSG_WriteByte(&buf, clc_nop); + if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1) + { + Con_Printf ("CL_SendCmd: lost server connection\n"); + CL_Disconnect (); + } + } } } #endif @@ -905,6 +1300,8 @@ void CL_SendCmd (void) if (!NET_CanSendMessage (cls.netcon)) { Con_DPrintf ("CL_WriteToServer: can't send\n"); + if (developer.integer) + SZ_HexDumpToConsole(&cls.message); return; } @@ -1030,7 +1427,6 @@ void CL_Init (void) Cvar_RegisterVariable (&cl_itembobheight); Cmd_AddCommand ("entities", CL_PrintEntities_f); - Cmd_AddCommand ("bitprofile", CL_BitProfile_f); Cmd_AddCommand ("disconnect", CL_Disconnect_f); Cmd_AddCommand ("record", CL_Record_f); Cmd_AddCommand ("stop", CL_Stop_f); @@ -1047,6 +1443,9 @@ void CL_Init (void) Cvar_RegisterVariable(&r_draweffects); Cvar_RegisterVariable(&cl_explosions); Cvar_RegisterVariable(&cl_stainmaps); + Cvar_RegisterVariable(&cl_beampolygons); + + R_LightningBeams_Init(); CL_Parse_Init(); CL_Particles_Init();