From e0c11b2f870eaf072f9c71727b2579fae5c627e3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Apr 2001 21:53:09 +0000 Subject: [PATCH] grr, it was r_part.c, not r_efrag, but that's sorted properly now --- nq/source/Makefile.am | 2 +- nq/source/r_part.c | 644 +++++++++++++++++++++++++++++++++ nq/source/r_view.c | 804 ++++++++++++++++++++++++++++++++++++++++++ nq/source/sw_refrag.c | 276 +++++++++++++++ 4 files changed, 1725 insertions(+), 1 deletion(-) create mode 100644 nq/source/r_part.c create mode 100644 nq/source/r_view.c create mode 100644 nq/source/sw_refrag.c diff --git a/nq/source/Makefile.am b/nq/source/Makefile.am index 1284a0a09..24fc55712 100644 --- a/nq/source/Makefile.am +++ b/nq/source/Makefile.am @@ -131,7 +131,7 @@ client_LIBS= $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs client_LIB_DEPS= libqfsys.a libqfsnd.a libqfcd.a libqfjs.a libqfnet.a client_SOURCES= cl_cam.c cl_cmd.c cl_demo.c cl_input.c cl_main.c cl_parse.c \ - cl_tent.c console.c keys.c sbar.c sw_rpart.c sw_rview.c \ + cl_tent.c console.c keys.c sbar.c r_part.c r_view.c \ nonintel.c gib.c gib_instructions.c gib_vars.c \ gib_interpret.c gib_modules.c gib_parse.c gib_stack.c vid.c diff --git a/nq/source/r_part.c b/nq/source/r_part.c new file mode 100644 index 000000000..68bff39eb --- /dev/null +++ b/nq/source/r_part.c @@ -0,0 +1,644 @@ + +/* + r_part.c + + @description@ + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "r_local.h" +#include "QF/qargs.h" +#include "QF/console.h" +#include "server.h" +#include "QF/msg.h" + +#define MAX_PARTICLES 2048 // default max # of particles at one + // time +#define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter + // what's + // on the command line + +int ramp1[8] = { 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61 }; +int ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 }; +int ramp3[8] = { 0x6d, 0x6b, 6, 5, 4, 3 }; + +particle_t *active_particles, *free_particles; + +particle_t *particles; +int r_numparticles; + +vec3_t r_pright, r_pup, r_ppn; + +extern cvar_t *gl_particles; + +/* +=============== +R_InitParticles +=============== +*/ +void +R_InitParticles (void) +{ + int i; + + i = COM_CheckParm ("-particles"); + + if (i) { + r_numparticles = (int) (atoi (com_argv[i + 1])); + if (r_numparticles < ABSOLUTE_MIN_PARTICLES) + r_numparticles = ABSOLUTE_MIN_PARTICLES; + } else { + r_numparticles = MAX_PARTICLES; + } + + particles = (particle_t *) + Hunk_AllocName (r_numparticles * sizeof (particle_t), "particles"); +} + +#ifdef QUAKE2 +void +R_DarkFieldParticles (entity_t *ent) +{ + int i, j, k; + particle_t *p; + float vel; + vec3_t dir; + vec3_t org; + + org[0] = ent->origin[0]; + org[1] = ent->origin[1]; + org[2] = ent->origin[2]; + for (i = -16; i < 16; i += 8) + for (j = -16; j < 16; j += 8) + for (k = 0; k < 32; k += 8) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 0.2 + (rand () & 7) * 0.02; + p->color = 150 + rand () % 6; + p->type = pt_slowgrav; + + dir[0] = j * 8; + dir[1] = i * 8; + dir[2] = k * 8; + + p->org[0] = org[0] + i + (rand () & 3); + p->org[1] = org[1] + j + (rand () & 3); + p->org[2] = org[2] + k + (rand () & 3); + + VectorNormalize (dir); + vel = 50 + (rand () & 63); + VectorScale (dir, vel, p->vel); + } +} +#endif + + +/* +=============== +R_EntityParticles +=============== +*/ + +#define NUMVERTEXNORMALS 162 +extern float r_avertexnormals[NUMVERTEXNORMALS][3]; +vec3_t avelocities[NUMVERTEXNORMALS]; +float beamlength = 16; +vec3_t avelocity = { 23, 7, 3 }; +float partstep = 0.01; +float timescale = 0.01; + +void +R_EntityParticles (entity_t *ent) +{ + int count; + int i; + particle_t *p; + float angle; + float sr, sp, sy, cr, cp, cy; + vec3_t forward; + float dist; + + dist = 64; + count = 50; + + if (!avelocities[0][0]) { + for (i = 0; i < NUMVERTEXNORMALS * 3; i++) + avelocities[0][i] = (rand () & 255) * 0.01; + } + + + for (i = 0; i < NUMVERTEXNORMALS; i++) { + angle = cl.time * avelocities[i][0]; + sy = sin (angle); + cy = cos (angle); + angle = cl.time * avelocities[i][1]; + sp = sin (angle); + cp = cos (angle); + angle = cl.time * avelocities[i][2]; + sr = sin (angle); + cr = cos (angle); + + forward[0] = cp * cy; + forward[1] = cp * sy; + forward[2] = -sp; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 0.01; + p->color = 0x6f; + p->type = pt_explode; + + p->org[0] = + ent->origin[0] + r_avertexnormals[i][0] * dist + + forward[0] * beamlength; + p->org[1] = + ent->origin[1] + r_avertexnormals[i][1] * dist + + forward[1] * beamlength; + p->org[2] = + ent->origin[2] + r_avertexnormals[i][2] * dist + + forward[2] * beamlength; + } +} + + +/* +=============== +R_ClearParticles +=============== +*/ +void +R_ClearParticles (void) +{ + int i; + + free_particles = &particles[0]; + active_particles = NULL; + + for (i = 0; i < r_numparticles; i++) + particles[i].next = &particles[i + 1]; + particles[r_numparticles - 1].next = NULL; +} + + +void +R_ReadPointFile_f (void) +{ + QFile *f; + vec3_t org; + int r; + int c; + particle_t *p; + char name[MAX_OSPATH]; + char buf[256]; + + snprintf (name, sizeof (name), "maps/%s.pts", sv.name); + + COM_FOpenFile (name, &f); + if (!f) { + Con_Printf ("couldn't open %s\n", name); + return; + } + + Con_Printf ("Reading %s...\n", name); + c = 0; + for (;;) { + if (!Qgets (f, buf, sizeof (buf))) + break; + r = sscanf (buf, "%f %f %f\n", &org[0], &org[1], &org[2]); + if (r != 3) + break; + c++; + + if (!free_particles) { + Con_Printf ("Not enough free particles\n"); + break; + } + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = 99999; + p->color = (-c) & 15; + p->type = pt_static; + VectorCopy (vec3_origin, p->vel); + VectorCopy (org, p->org); + } + + Qclose (f); + Con_Printf ("%i points read\n", c); +} + +/* +=============== +R_ParseParticleEffect + +Parse an effect out of the server message +=============== +*/ +void +R_ParseParticleEffect (void) +{ + vec3_t org, dir; + int i, count, msgcount, color; + + for (i = 0; i < 3; i++) + org[i] = MSG_ReadCoord (net_message); + for (i = 0; i < 3; i++) + dir[i] = MSG_ReadChar (net_message) * (1.0 / 16); + msgcount = MSG_ReadByte (net_message); + color = MSG_ReadByte (net_message); + + if (msgcount == 255) + count = 1024; + else + count = msgcount; + + R_RunParticleEffect (org, dir, color, count); +} + +/* +=============== +R_ParticleExplosion + +=============== +*/ +void +R_ParticleExplosion (vec3_t org) +{ + int i, j; + particle_t *p; + + for (i = 0; i < 1024; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 5; + p->color = ramp1[0]; + p->ramp = rand () & 3; + if (i & 1) { + p->type = pt_explode; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand () % 32) - 16); + p->vel[j] = (rand () % 512) - 256; + } + } else { + p->type = pt_explode2; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand () % 32) - 16); + p->vel[j] = (rand () % 512) - 256; + } + } + } +} + +/* +=============== +R_ParticleExplosion2 + +=============== +*/ +void +R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength) +{ + int i, j; + particle_t *p; + int colorMod = 0; + + for (i = 0; i < 512; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 0.3; + p->color = colorStart + (colorMod % colorLength); + colorMod++; + + p->type = pt_blob; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand () % 32) - 16); + p->vel[j] = (rand () % 512) - 256; + } + } +} + +/* +=============== +R_BlobExplosion + +=============== +*/ +void +R_BlobExplosion (vec3_t org) +{ + int i, j; + particle_t *p; + + for (i = 0; i < 1024; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 1 + (rand () & 8) * 0.05; + + if (i & 1) { + p->type = pt_blob; + p->color = 66 + rand () % 6; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand () % 32) - 16); + p->vel[j] = (rand () % 512) - 256; + } + } else { + p->type = pt_blob2; + p->color = 150 + rand () % 6; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand () % 32) - 16); + p->vel[j] = (rand () % 512) - 256; + } + } + } +} + +/* +=============== +R_RunParticleEffect + +=============== +*/ +void +R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) +{ + int i, j; + particle_t *p; + + for (i = 0; i < count; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + if (count == 1024) { // rocket explosion + p->die = cl.time + 5; + p->color = ramp1[0]; + p->ramp = rand () & 3; + if (i & 1) { + p->type = pt_explode; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand () % 32) - 16); + p->vel[j] = (rand () % 512) - 256; + } + } else { + p->type = pt_explode2; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand () % 32) - 16); + p->vel[j] = (rand () % 512) - 256; + } + } + } else { + p->die = cl.time + 0.1 * (rand () % 5); + p->color = (color & ~7) + (rand () & 7); + p->type = pt_slowgrav; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand () & 15) - 8); + p->vel[j] = dir[j] * 15; // + (rand()%300)-150; + } + } + } +} + + +/* +=============== +R_LavaSplash + +=============== +*/ +void +R_LavaSplash (vec3_t org) +{ + int i, j, k; + particle_t *p; + float vel; + vec3_t dir; + + for (i = -16; i < 16; i++) + for (j = -16; j < 16; j++) + for (k = 0; k < 1; k++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 2 + (rand () & 31) * 0.02; + p->color = 224 + (rand () & 7); + p->type = pt_slowgrav; + + dir[0] = j * 8 + (rand () & 7); + dir[1] = i * 8 + (rand () & 7); + dir[2] = 256; + + p->org[0] = org[0] + dir[0]; + p->org[1] = org[1] + dir[1]; + p->org[2] = org[2] + (rand () & 63); + + VectorNormalize (dir); + vel = 50 + (rand () & 63); + VectorScale (dir, vel, p->vel); + } +} + +/* +=============== +R_TeleportSplash + +=============== +*/ +void +R_TeleportSplash (vec3_t org) +{ + int i, j, k; + particle_t *p; + float vel; + vec3_t dir; + + for (i = -16; i < 16; i += 4) + for (j = -16; j < 16; j += 4) + for (k = -24; k < 32; k += 4) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 0.2 + (rand () & 7) * 0.02; + p->color = 7 + (rand () & 7); + p->type = pt_slowgrav; + + dir[0] = j * 8; + dir[1] = i * 8; + dir[2] = k * 8; + + p->org[0] = org[0] + i + (rand () & 3); + p->org[1] = org[1] + j + (rand () & 3); + p->org[2] = org[2] + k + (rand () & 3); + + VectorNormalize (dir); + vel = 50 + (rand () & 63); + VectorScale (dir, vel, p->vel); + } +} + +void +R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) +{ + vec3_t vec; + float len; + int j; + particle_t *p; + int dec; + static int tracercount; + + if (type == 0) + R_AddFire (start, end, ent); + + if (!gl_particles->int_val) + return; + + VectorSubtract (end, start, vec); + len = VectorNormalize (vec); + if (type < 128) + dec = 3; + else { + dec = 1; + type -= 128; + } + + while (len > 0) { + len -= dec; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + VectorCopy (vec3_origin, p->vel); + p->die = cl.time + 2; + + switch (type) { + case 0: // rocket trail + p->ramp = (rand () & 3); + p->color = ramp3[(int) p->ramp]; + p->type = pt_fire; + for (j = 0; j < 3; j++) + p->org[j] = start[j] + ((rand () % 6) - 3); + break; + + case 1: // smoke smoke + p->ramp = (rand () & 3) + 2; + p->color = ramp3[(int) p->ramp]; + p->type = pt_fire; + for (j = 0; j < 3; j++) + p->org[j] = start[j] + ((rand () % 6) - 3); + break; + + case 2: // blood + p->type = pt_grav; + p->color = 67 + (rand () & 3); + for (j = 0; j < 3; j++) + p->org[j] = start[j] + ((rand () % 6) - 3); + break; + + case 3: + case 5: // tracer + p->die = cl.time + 0.5; + p->type = pt_static; + if (type == 3) + p->color = 52 + ((tracercount & 4) << 1); + else + p->color = 230 + ((tracercount & 4) << 1); + + tracercount++; + + VectorCopy (start, p->org); + if (tracercount & 1) { + p->vel[0] = 30 * vec[1]; + p->vel[1] = 30 * -vec[0]; + } else { + p->vel[0] = 30 * -vec[1]; + p->vel[1] = 30 * vec[0]; + } + break; + + case 4: // slight blood + p->type = pt_grav; + p->color = 67 + (rand () & 3); + for (j = 0; j < 3; j++) + p->org[j] = start[j] + ((rand () % 6) - 3); + len -= 3; + break; + + case 6: // voor trail + p->color = 9 * 16 + 8 + (rand () & 3); + p->type = pt_static; + p->die = cl.time + 0.3; + for (j = 0; j < 3; j++) + p->org[j] = start[j] + ((rand () & 15) - 8); + break; + } + + + VectorAdd (start, vec, start); + } +} diff --git a/nq/source/r_view.c b/nq/source/r_view.c new file mode 100644 index 000000000..f7f77612c --- /dev/null +++ b/nq/source/r_view.c @@ -0,0 +1,804 @@ +/* + view.c + + @description@ + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "view.h" +#include "r_local.h" +#include "host.h" +#include "QF/cmd.h" +#include "chase.h" +#include "draw.h" +#include "screen.h" +#include "QF/console.h" +#include "QF/msg.h" + +/* + +The view is allowed to move slightly from it's true position for bobbing, +but if it exceeds 8 pixels linear distance (spherical, not box), the list of +entities sent from the server may not include everything in the pvs, especially +when crossing a water boudnary. + +*/ + +cvar_t *scr_ofsx; +cvar_t *scr_ofsy; +cvar_t *scr_ofsz; + +cvar_t *cl_rollspeed; +cvar_t *cl_rollangle; + +cvar_t *cl_bob; +cvar_t *cl_bobcycle; +cvar_t *cl_bobup; + +cvar_t *v_kicktime; +cvar_t *v_kickroll; +cvar_t *v_kickpitch; + +cvar_t *v_iyaw_cycle; +cvar_t *v_iroll_cycle; +cvar_t *v_ipitch_cycle; +cvar_t *v_iyaw_level; +cvar_t *v_iroll_level; +cvar_t *v_ipitch_level; + +cvar_t *v_idlescale; + +cvar_t *crosshair; +cvar_t *crosshaircolor; +cvar_t *cl_crossx; +cvar_t *cl_crossy; + +cvar_t *gl_cshiftpercent; + +cvar_t *brightness; +cvar_t *contrast; + +float v_dmg_time, v_dmg_roll, v_dmg_pitch; + +extern int in_forward, in_forward2, in_back; + +void BuildGammaTable (float, float); + +/* +=============== +V_CalcBob + +=============== +*/ +float +V_CalcBob (void) +{ + float bob; + float cycle; + + cycle = cl.time - (int) (cl.time / cl_bobcycle->value) * cl_bobcycle->value; + cycle /= cl_bobcycle->value; + if (cycle < cl_bobup->value) + cycle = M_PI * cycle / cl_bobup->value; + else + cycle = + M_PI + M_PI * (cycle - cl_bobup->value) / (1.0 - cl_bobup->value); + +// bob is proportional to velocity in the xy plane +// (don't count Z, or jumping messes it up) + + bob = + sqrt (cl.velocity[0] * cl.velocity[0] + + cl.velocity[1] * cl.velocity[1]) * cl_bob->value; +//Con_Printf ("speed: %5.1f\n", Length(cl.velocity)); + bob = bob * 0.3 + bob * 0.7 * sin (cycle); + if (bob > 4) + bob = 4; + else if (bob < -7) + bob = -7; + return bob; + +} + + +//============================================================================= + + +cvar_t *v_centermove; +cvar_t *v_centerspeed; + + +void +V_StartPitchDrift (void) +{ +#if 1 + if (cl.laststop == cl.time) { + return; // something else is keeping it from + // drifting + } +#endif + if (cl.nodrift || !cl.pitchvel) { + cl.pitchvel = v_centerspeed->value; + cl.nodrift = false; + cl.driftmove = 0; + } +} + +void +V_StopPitchDrift (void) +{ + cl.laststop = cl.time; + cl.nodrift = true; + cl.pitchvel = 0; +} + +/* +=============== +V_DriftPitch + +Moves the client pitch angle towards cl.idealpitch sent by the server. + +If the user is adjusting pitch manually, either with lookup/lookdown, +mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. + +Drifting is enabled when the center view key is hit, mlook is released and +lookspring is non 0, or when +=============== +*/ +void +V_DriftPitch (void) +{ + float delta, move; + + if (noclip_anglehack || !cl.onground || cls.demoplayback) { + cl.driftmove = 0; + cl.pitchvel = 0; + return; + } +// don't count small mouse motion + if (cl.nodrift) { + if (fabs (cl.cmd.forwardmove) < cl_forwardspeed->value) + cl.driftmove = 0; + else + cl.driftmove += host_frametime; + + if (cl.driftmove > v_centermove->value) { + V_StartPitchDrift (); + } + return; + } + + delta = cl.idealpitch - cl.viewangles[PITCH]; + + if (!delta) { + cl.pitchvel = 0; + return; + } + + move = host_frametime * cl.pitchvel; + cl.pitchvel += host_frametime * v_centerspeed->value; + +//Con_Printf ("move: %f (%f)\n", move, host_frametime); + + if (delta > 0) { + if (move > delta) { + cl.pitchvel = 0; + move = delta; + } + cl.viewangles[PITCH] += move; + } else if (delta < 0) { + if (move > -delta) { + cl.pitchvel = 0; + move = -delta; + } + cl.viewangles[PITCH] -= move; + } +} + + + + + +/* +============================================================================== + + PALETTE FLASHES + +============================================================================== +*/ + + +cshift_t cshift_empty = { {130, 80, 50} +, 0 +}; +cshift_t cshift_water = { {130, 80, 50} +, 128 +}; +cshift_t cshift_slime = { {0, 25, 5} +, 150 +}; +cshift_t cshift_lava = { {255, 80, 0} +, 150 +}; + +cvar_t *v_gamma; + +byte gammatable[256]; // palette is sent through this + +/* +================= +V_CheckGamma +================= +*/ +qboolean +V_CheckGamma (void) +{ + static float oldbrightness; + static float oldcontrast; + + if ((brightness->value == oldbrightness) && contrast->value == oldcontrast) + return false; + oldbrightness = brightness->value; + oldcontrast = contrast->value; + + BuildGammaTable (brightness->value, contrast->value); + vid.recalc_refdef = 1; // force a surface cache flush + + return true; +} + + +/* +=============== +V_ParseDamage +=============== +*/ +void +V_ParseDamage (void) +{ + int armor, blood; + vec3_t from; + int i; + vec3_t forward, right, up; + entity_t *ent; + float side; + float count; + + armor = MSG_ReadByte (net_message); + blood = MSG_ReadByte (net_message); + for (i = 0; i < 3; i++) + from[i] = MSG_ReadCoord (net_message); + + count = blood * 0.5 + armor * 0.5; + if (count < 10) + count = 10; + + cl.faceanimtime = cl.time + 0.2; // but sbar face into pain frame + + cl.cshifts[CSHIFT_DAMAGE].percent += 3 * count; + if (cl.cshifts[CSHIFT_DAMAGE].percent < 0) + cl.cshifts[CSHIFT_DAMAGE].percent = 0; + if (cl.cshifts[CSHIFT_DAMAGE].percent > 150) + cl.cshifts[CSHIFT_DAMAGE].percent = 150; + + if (armor > blood) { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; + } else if (armor) { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; + } else { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; + } + +// +// calculate view angle kicks +// + ent = &cl_entities[cl.viewentity]; + + VectorSubtract (from, ent->origin, from); + VectorNormalize (from); + + AngleVectors (ent->angles, forward, right, up); + + side = DotProduct (from, right); + v_dmg_roll = count * side * v_kickroll->value; + + side = DotProduct (from, forward); + v_dmg_pitch = count * side * v_kickpitch->value; + + v_dmg_time = v_kicktime->value; +} + + +/* +================== +V_cshift_f +================== +*/ +void +V_cshift_f (void) +{ + cshift_empty.destcolor[0] = atoi (Cmd_Argv (1)); + cshift_empty.destcolor[1] = atoi (Cmd_Argv (2)); + cshift_empty.destcolor[2] = atoi (Cmd_Argv (3)); + cshift_empty.percent = atoi (Cmd_Argv (4)); +} + + +/* +================== +V_BonusFlash_f + +When you run over an item, the server sends this command +================== +*/ +void +V_BonusFlash_f (void) +{ + cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215; + cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186; + cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69; + cl.cshifts[CSHIFT_BONUS].percent = 50; +} + +/* +============= +V_SetContentsColor + +Underwater, lava, etc each has a color shift +============= +*/ +void +V_SetContentsColor (int contents) +{ + switch (contents) { + case CONTENTS_EMPTY: + case CONTENTS_SOLID: + cl.cshifts[CSHIFT_CONTENTS] = cshift_empty; + break; + case CONTENTS_LAVA: + cl.cshifts[CSHIFT_CONTENTS] = cshift_lava; + break; + case CONTENTS_SLIME: + cl.cshifts[CSHIFT_CONTENTS] = cshift_slime; + break; + default: + cl.cshifts[CSHIFT_CONTENTS] = cshift_water; + } +} + +/* +============= +V_CalcPowerupCshift +============= +*/ +void +V_CalcPowerupCshift (void) +{ + if (cl.items & IT_QUAD) { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255; + cl.cshifts[CSHIFT_POWERUP].percent = 30; + } else if (cl.items & IT_SUIT) { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; + cl.cshifts[CSHIFT_POWERUP].percent = 20; + } else if (cl.items & IT_INVISIBILITY) { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100; + cl.cshifts[CSHIFT_POWERUP].percent = 100; + } else if (cl.items & IT_INVULNERABILITY) { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; + cl.cshifts[CSHIFT_POWERUP].percent = 30; + } else + cl.cshifts[CSHIFT_POWERUP].percent = 0; +} + + +/* +============================================================================== + + VIEW RENDERING + +============================================================================== +*/ + +float +angledelta (float a) +{ + a = anglemod (a); + if (a > 180) + a -= 360; + return a; +} + +/* +================== +CalcGunAngle +================== +*/ +void +CalcGunAngle (void) +{ + float yaw, pitch, move; + static float oldyaw = 0; + static float oldpitch = 0; + + yaw = r_refdef.viewangles[YAW]; + pitch = -r_refdef.viewangles[PITCH]; + + yaw = angledelta (yaw - r_refdef.viewangles[YAW]) * 0.4; + if (yaw > 10) + yaw = 10; + if (yaw < -10) + yaw = -10; + pitch = angledelta (-pitch - r_refdef.viewangles[PITCH]) * 0.4; + if (pitch > 10) + pitch = 10; + if (pitch < -10) + pitch = -10; + move = host_frametime * 20; + if (yaw > oldyaw) { + if (oldyaw + move < yaw) + yaw = oldyaw + move; + } else { + if (oldyaw - move > yaw) + yaw = oldyaw - move; + } + + if (pitch > oldpitch) { + if (oldpitch + move < pitch) + pitch = oldpitch + move; + } else { + if (oldpitch - move > pitch) + pitch = oldpitch - move; + } + + oldyaw = yaw; + oldpitch = pitch; + + cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw; + cl.viewent.angles[PITCH] = -(r_refdef.viewangles[PITCH] + pitch); + + cl.viewent.angles[ROLL] -= + v_idlescale->value * sin (cl.time * v_iroll_cycle->value) * + v_iroll_level->value; + cl.viewent.angles[PITCH] -= + v_idlescale->value * sin (cl.time * v_ipitch_cycle->value) * + v_ipitch_level->value; + cl.viewent.angles[YAW] -= + v_idlescale->value * sin (cl.time * v_iyaw_cycle->value) * + v_iyaw_level->value; +} + +/* +============== +V_BoundOffsets +============== +*/ +void +V_BoundOffsets (void) +{ + entity_t *ent; + + ent = &cl_entities[cl.viewentity]; + +// absolutely bound refresh reletive to entity clipping hull +// so the view can never be inside a solid wall + + if (r_refdef.vieworg[0] < ent->origin[0] - 14) + r_refdef.vieworg[0] = ent->origin[0] - 14; + else if (r_refdef.vieworg[0] > ent->origin[0] + 14) + r_refdef.vieworg[0] = ent->origin[0] + 14; + if (r_refdef.vieworg[1] < ent->origin[1] - 14) + r_refdef.vieworg[1] = ent->origin[1] - 14; + else if (r_refdef.vieworg[1] > ent->origin[1] + 14) + r_refdef.vieworg[1] = ent->origin[1] + 14; + if (r_refdef.vieworg[2] < ent->origin[2] - 22) + r_refdef.vieworg[2] = ent->origin[2] - 22; + else if (r_refdef.vieworg[2] > ent->origin[2] + 30) + r_refdef.vieworg[2] = ent->origin[2] + 30; +} + +/* +============== +V_AddIdle + +Idle swaying +============== +*/ +void +V_AddIdle (void) +{ + r_refdef.viewangles[ROLL] += + v_idlescale->value * sin (cl.time * v_iroll_cycle->value) * + v_iroll_level->value; + r_refdef.viewangles[PITCH] += + v_idlescale->value * sin (cl.time * v_ipitch_cycle->value) * + v_ipitch_level->value; + r_refdef.viewangles[YAW] += + v_idlescale->value * sin (cl.time * v_iyaw_cycle->value) * + v_iyaw_level->value; +} + + +/* +============== +V_CalcViewRoll + +Roll is induced by movement and damage +============== +*/ +void +V_CalcViewRoll (void) +{ + float side; + + side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity); + r_refdef.viewangles[ROLL] += side; + + if (v_dmg_time > 0) { + r_refdef.viewangles[ROLL] += + v_dmg_time / v_kicktime->value * v_dmg_roll; + r_refdef.viewangles[PITCH] += + v_dmg_time / v_kicktime->value * v_dmg_pitch; + v_dmg_time -= host_frametime; + } + + if (cl.stats[STAT_HEALTH] <= 0) { + r_refdef.viewangles[ROLL] = 80; // dead view angle + return; + } + +} + + +/* +================== +V_CalcIntermissionRefdef + +================== +*/ +void +V_CalcIntermissionRefdef (void) +{ + entity_t *ent, *view; + float old; + +// ent is the player model (visible when out of body) + ent = &cl_entities[cl.viewentity]; +// view is the weapon model (only visible from inside body) + view = &cl.viewent; + + VectorCopy (ent->origin, r_refdef.vieworg); + VectorCopy (ent->angles, r_refdef.viewangles); + view->model = NULL; + +// always idle in intermission + old = v_idlescale->value; + Cvar_SetValue (v_idlescale, 1); + V_AddIdle (); + Cvar_SetValue (v_idlescale, old); +} + +/* +================== +V_CalcRefdef + +================== +*/ +void +V_CalcRefdef (void) +{ + entity_t *ent, *view; + int i; + vec3_t forward, right, up; + vec3_t angles; + float bob; + static float oldz = 0; + + V_DriftPitch (); + +// ent is the player model (visible when out of body) + ent = &cl_entities[cl.viewentity]; +// view is the weapon model (only visible from inside body) + view = &cl.viewent; + + +// transform the view offset by the model's matrix to get the offset from +// model origin for the view + ent->angles[YAW] = cl.viewangles[YAW]; // the model should face + // the view dir + ent->angles[PITCH] = -cl.viewangles[PITCH]; // the model should face + // the view dir + + + bob = V_CalcBob (); + +// refresh position + VectorCopy (ent->origin, r_refdef.vieworg); + r_refdef.vieworg[2] += cl.viewheight + bob; + +// never let it sit exactly on a node line, because a water plane can +// dissapear when viewed with the eye exactly on it. +// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + r_refdef.vieworg[0] += 1.0 / 32; + r_refdef.vieworg[1] += 1.0 / 32; + r_refdef.vieworg[2] += 1.0 / 32; + + VectorCopy (cl.viewangles, r_refdef.viewangles); + V_CalcViewRoll (); + V_AddIdle (); + +// offsets + angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are + // actually backward + angles[YAW] = ent->angles[YAW]; + angles[ROLL] = ent->angles[ROLL]; + + AngleVectors (angles, forward, right, up); + + for (i = 0; i < 3; i++) + r_refdef.vieworg[i] += scr_ofsx->value * forward[i] + + scr_ofsy->value * right[i] + + scr_ofsz->value * up[i]; + + + V_BoundOffsets (); + +// set up gun position + VectorCopy (cl.viewangles, view->angles); + + CalcGunAngle (); + + VectorCopy (ent->origin, view->origin); + view->origin[2] += cl.viewheight; + + for (i = 0; i < 3; i++) { + view->origin[i] += forward[i] * bob * 0.4; +// view->origin[i] += right[i]*bob*0.4; +// view->origin[i] += up[i]*bob*0.8; + } + view->origin[2] += bob; + +// fudge position around to keep amount of weapon visible +// roughly equal with different FOV + +#if 0 + if (cl.model_precache[cl.stats[STAT_WEAPON]] + && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name, + "progs/v_shot2.mdl")) +#endif + if (cl_sbar->int_val == 0 && scr_viewsize->int_val >= 100); + else if (scr_viewsize->int_val == 110) + view->origin[2] += 1; + else if (scr_viewsize->int_val == 100) + view->origin[2] += 2; + else if (scr_viewsize->int_val == 90) + view->origin[2] += 1; + else if (scr_viewsize->int_val == 80) + view->origin[2] += 0.5; + + view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; + view->frame = cl.stats[STAT_WEAPONFRAME]; + view->colormap = vid.colormap; + +// set up the refresh position + VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles); + +// smooth out stair step ups + if (cl.onground && ent->origin[2] - oldz > 0) { + float steptime; + + steptime = cl.time - cl.oldtime; + if (steptime < 0) +//FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 80; + if (oldz > ent->origin[2]) + oldz = ent->origin[2]; + if (ent->origin[2] - oldz > 12) + oldz = ent->origin[2] - 12; + r_refdef.vieworg[2] += oldz - ent->origin[2]; + view->origin[2] += oldz - ent->origin[2]; + } else + oldz = ent->origin[2]; + + if (chase_active->int_val) + Chase_Update (); +} + +/* +================== +V_RenderView + +The player's clipping box goes from (-16 -16 -24) to (16 16 32) from +the entity origin, so any view position inside that will be valid +================== +*/ +extern vrect_t scr_vrect; + +//============================================================================ + +/* +============= +V_Init +============= +*/ +void +V_Init (void) +{ + Cmd_AddCommand ("v_cshift", V_cshift_f, "No Description"); + Cmd_AddCommand ("bf", V_BonusFlash_f, "No Description"); + Cmd_AddCommand ("centerview", V_StartPitchDrift, "No Description"); + + v_centermove = Cvar_Get ("v_centermove", "0.15", CVAR_NONE, 0, "None"); + v_centerspeed = Cvar_Get ("v_centerspeed", "500", CVAR_NONE, 0, "None"); + + v_iyaw_cycle = Cvar_Get ("v_iyaw_cycle", "2", CVAR_NONE, 0, "None"); + v_iroll_cycle = Cvar_Get ("v_iroll_cycle", "0.5", CVAR_NONE, 0, "None"); + v_ipitch_cycle = Cvar_Get ("v_ipitch_cycle", "1", CVAR_NONE, 0, "None"); + v_iyaw_level = Cvar_Get ("v_iyaw_level", "0.3", CVAR_NONE, 0, "None"); + v_iroll_level = Cvar_Get ("v_iroll_level", "0.1", CVAR_NONE, 0, "None"); + v_ipitch_level = Cvar_Get ("v_ipitch_level", "0.3", CVAR_NONE, 0, "None"); + + v_idlescale = Cvar_Get ("v_idlescale", "0", CVAR_NONE, 0, "None"); + crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE, 0, "None"); + crosshaircolor = Cvar_Get ("crosshaircolor", "79", CVAR_ARCHIVE, 0, "None"); + cl_crossx = Cvar_Get ("cl_crossx", "0", CVAR_NONE, 0, "None"); + cl_crossy = Cvar_Get ("cl_crossy", "0", CVAR_NONE, 0, "None"); + gl_cshiftpercent = Cvar_Get ("gl_cshiftpercent", "100", CVAR_NONE, 0, "None"); + + scr_ofsx = Cvar_Get ("scr_ofsx", "0", CVAR_NONE, 0, "None"); + scr_ofsy = Cvar_Get ("scr_ofsy", "0", CVAR_NONE, 0, "None"); + scr_ofsz = Cvar_Get ("scr_ofsz", "0", CVAR_NONE, 0, "None"); + cl_rollspeed = Cvar_Get ("cl_rollspeed", "200", CVAR_NONE, 0, "None"); + cl_rollangle = Cvar_Get ("cl_rollangle", "2.0", CVAR_NONE, 0, "None"); + cl_bob = Cvar_Get ("cl_bob", "0.02", CVAR_NONE, 0, "None"); + cl_bobcycle = Cvar_Get ("cl_bobcycle", "0.6", CVAR_NONE, 0, "None"); + cl_bobup = Cvar_Get ("cl_bobup", "0.5", CVAR_NONE, 0, "None"); + + v_kicktime = Cvar_Get ("v_kicktime", "0.5", CVAR_NONE, 0, "None"); + v_kickroll = Cvar_Get ("v_kickroll", "0.6", CVAR_NONE, 0, "None"); + v_kickpitch = Cvar_Get ("v_kickpitch", "0.6", CVAR_NONE, 0, "None"); + + BuildGammaTable (1.0, 1.0); // no gamma yet + brightness = Cvar_Get ("brightness", "1", CVAR_ARCHIVE, 0, "None"); + contrast = Cvar_Get ("contrast", "1", CVAR_ARCHIVE, 0, "None"); +} diff --git a/nq/source/sw_refrag.c b/nq/source/sw_refrag.c new file mode 100644 index 000000000..c10d67b05 --- /dev/null +++ b/nq/source/sw_refrag.c @@ -0,0 +1,276 @@ +/* + r_efrag.c + + @description@ + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/console.h" +#include "QF/sys.h" +#include "r_local.h" + +mnode_t *r_pefragtopnode; + + +//=========================================================================== + +/* +=============================================================================== + + ENTITY FRAGMENT FUNCTIONS + +=============================================================================== +*/ + +efrag_t **lastlink; + +vec3_t r_emins, r_emaxs; + +entity_t *r_addent; + + +/* +================ +R_RemoveEfrags + +Call when removing an object from the world or moving it to another position +================ +*/ +void +R_RemoveEfrags (entity_t *ent) +{ + efrag_t *ef, *old, *walk, **prev; + + ef = ent->efrag; + + while (ef) { + prev = &ef->leaf->efrags; + while (1) { + walk = *prev; + if (!walk) + break; + if (walk == ef) { // remove this fragment + *prev = ef->leafnext; + break; + } else + prev = &walk->leafnext; + } + + old = ef; + ef = ef->entnext; + + // put it on the free list + old->entnext = cl.free_efrags; + cl.free_efrags = old; + } + + ent->efrag = NULL; +} + +/* +=================== +R_SplitEntityOnNode +=================== +*/ +void +R_SplitEntityOnNode (mnode_t *node) +{ + efrag_t *ef; + mplane_t *splitplane; + mleaf_t *leaf; + int sides; + + if (node->contents == CONTENTS_SOLID) { + return; + } +// add an efrag if the node is a leaf + + if (node->contents < 0) { + if (!r_pefragtopnode) + r_pefragtopnode = node; + + leaf = (mleaf_t *) node; + +// grab an efrag off the free list + ef = cl.free_efrags; + if (!ef) { + Con_Printf ("Too many efrags!\n"); + return; // no free fragments... + } + cl.free_efrags = cl.free_efrags->entnext; + + ef->entity = r_addent; + +// add the entity link + *lastlink = ef; + lastlink = &ef->entnext; + ef->entnext = NULL; + +// set the leaf links + ef->leaf = leaf; + ef->leafnext = leaf->efrags; + leaf->efrags = ef; + + return; + } +// NODE_MIXED + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE (r_emins, r_emaxs, splitplane); + + if (sides == 3) { + // split on this plane + // if this is the first splitter of this bmodel, remember it + if (!r_pefragtopnode) + r_pefragtopnode = node; + } +// recurse down the contacted sides + if (sides & 1) + R_SplitEntityOnNode (node->children[0]); + + if (sides & 2) + R_SplitEntityOnNode (node->children[1]); +} + + +/* +=================== +R_SplitEntityOnNode2 +=================== +*/ +void +R_SplitEntityOnNode2 (mnode_t *node) +{ + mplane_t *splitplane; + int sides; + + if (node->visframe != r_visframecount) + return; + + if (node->contents < 0) { + if (node->contents != CONTENTS_SOLID) + r_pefragtopnode = node; // we've reached a non-solid leaf, so + // + // + // it's + // visible and not BSP clipped + return; + } + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE (r_emins, r_emaxs, splitplane); + + if (sides == 3) { + // remember first splitter + r_pefragtopnode = node; + return; + } +// not split yet; recurse down the contacted side + if (sides & 1) + R_SplitEntityOnNode2 (node->children[0]); + else + R_SplitEntityOnNode2 (node->children[1]); +} + + +/* +=========== +R_AddEfrags +=========== +*/ +void +R_AddEfrags (entity_t *ent) +{ + model_t *entmodel; + int i; + + if (!ent->model) + return; + + if (ent == cl_entities) + return; // never add the world + + r_addent = ent; + + lastlink = &ent->efrag; + r_pefragtopnode = NULL; + + entmodel = ent->model; + + for (i = 0; i < 3; i++) { + r_emins[i] = ent->origin[i] + entmodel->mins[i]; + r_emaxs[i] = ent->origin[i] + entmodel->maxs[i]; + } + + R_SplitEntityOnNode (cl.worldmodel->nodes); + + ent->topnode = r_pefragtopnode; +} + + +/* +================ +R_StoreEfrags + +// FIXME: a lot of this goes away with edge-based +================ +*/ +void +R_StoreEfrags (efrag_t **ppefrag) +{ + entity_t *pent; + model_t *clmodel; + efrag_t *pefrag; + + + while ((pefrag = *ppefrag) != NULL) { + pent = pefrag->entity; + clmodel = pent->model; + + switch (clmodel->type) { + case mod_alias: + case mod_brush: + case mod_sprite: + pent = pefrag->entity; + + if ((pent->visframe != r_framecount) && + (cl_numvisedicts < MAX_VISEDICTS)) { + cl_visedicts[cl_numvisedicts++] = pent; + + // mark that we've recorded this entity for this frame + pent->visframe = r_framecount; + } + + ppefrag = &pefrag->leafnext; + break; + + default: + Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type); + } + } +}