mirror of
https://git.code.sf.net/p/quake/newtree
synced 2025-01-21 07:30:55 +00:00
A little more progress
This commit is contained in:
parent
2464548ffd
commit
9adb98d87e
7 changed files with 1557 additions and 156 deletions
|
@ -20,6 +20,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
// disable data conversion warnings
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable : 4244) // MIPS
|
||||
#pragma warning(disable : 4136) // X86
|
||||
#pragma warning(disable : 4051) // ALPHA
|
||||
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
@ -235,8 +239,8 @@ void GL_Bind (int texnum);
|
|||
#define TEXTURE1_SGIS 0x835F
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef void (APIENTRY *lpMTexFUNC) (GLenum, GLfloat, GLfloat);
|
||||
typedef void (APIENTRY *lpSelTexFUNC) (GLenum);
|
||||
typedef void (GLAPIENTRY *lpMTexFUNC) (GLenum, GLfloat, GLfloat);
|
||||
typedef void (GLAPIENTRY *lpSelTexFUNC) (GLenum);
|
||||
extern lpMTexFUNC qglMTexCoord2fSGIS;
|
||||
extern lpSelTexFUNC qglSelectTextureSGIS;
|
||||
#endif
|
||||
|
@ -270,6 +274,9 @@ void R_RotateForEntity (entity_t *e);
|
|||
//
|
||||
// gl_rlight.c
|
||||
//
|
||||
|
||||
extern float v_blend[4];
|
||||
|
||||
void R_MarkLights (dlight_t *light, int bit, mnode_t *node);
|
||||
void R_AnimateLight (void);
|
||||
void R_RenderDlights (void);
|
||||
|
|
|
@ -56,12 +56,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "render.h"
|
||||
#include "client.h"
|
||||
|
||||
#ifdef GLQUAKE
|
||||
#include "gl_model.h"
|
||||
#else
|
||||
#include "model.h"
|
||||
#include "d_iface.h"
|
||||
#endif
|
||||
//#ifdef GLQUAKE
|
||||
//#include "gl_model.h"
|
||||
//#else
|
||||
//#include "model.h"
|
||||
//#include "d_iface.h"
|
||||
//#endif
|
||||
|
||||
#include "input.h"
|
||||
#include "keys.h"
|
||||
|
@ -72,9 +72,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "cdaudio.h"
|
||||
#include "pmove.h"
|
||||
|
||||
#ifdef GLQUAKE
|
||||
#include "glquake.h"
|
||||
#endif
|
||||
//#ifdef GLQUAKE
|
||||
//#include "glquake.h"
|
||||
//#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
|
|
@ -10,12 +10,16 @@ CL_X11_name=qw-client-x11
|
|||
CL_X11_libs=-lX11 -lXext
|
||||
|
||||
CL_GLX_name=qw-client-glx
|
||||
CL_GLX_libs=-lX11 -lXext
|
||||
CL_GLX_libs=-lX11 -lXext -lGL
|
||||
|
||||
DIRECTORIES=
|
||||
vpath %.a $(patsubst @%,%,$(DIRECTORIES)) /usr/lib
|
||||
|
||||
CPPFLAGS=-I . -I ../include -DELF -Did386=1 -MMD -Dstricmp=strcasecmp
|
||||
|
||||
gcc -I . -I ../include -DELF -Did386=1 -MMD -Dstricmp=strcasecmp -c -o gl_draw.o gl_draw.c
|
||||
|
||||
|
||||
CFLAGS=-Wall -Werror
|
||||
CXXFLAGS=-Wall -Werror
|
||||
LDFLAGS=-L/usr/X11R6/lib
|
||||
|
@ -96,10 +100,12 @@ CL_SW_sources=\
|
|||
r_light.c \
|
||||
r_main.c \
|
||||
r_misc.c \
|
||||
r_part.c \
|
||||
r_sky.c \
|
||||
r_sprite.c \
|
||||
r_surf.c \
|
||||
r_vars.c \
|
||||
r_view.c \
|
||||
screen.c \
|
||||
d_copy.S \
|
||||
d_draw.S \
|
||||
|
@ -140,13 +146,11 @@ CL_sources=\
|
|||
sys_linux.c \
|
||||
cd_linux.c \
|
||||
wad.c \
|
||||
view.c \
|
||||
snd_dma.c \
|
||||
snd_mem.c \
|
||||
snd_mix.c \
|
||||
skin.c \
|
||||
sbar.c \
|
||||
r_part.c \
|
||||
nonintel.c \
|
||||
menu.c \
|
||||
keys.c \
|
||||
|
@ -172,12 +176,14 @@ CL_GLX_sources=\
|
|||
gl_mesh.c \
|
||||
gl_model.c \
|
||||
gl_ngraph.c \
|
||||
gl_part.c \
|
||||
gl_refrag.c \
|
||||
gl_rlight.c \
|
||||
gl_rmain.c \
|
||||
gl_rmisc.c \
|
||||
gl_rsurf.c \
|
||||
gl_screen.c \
|
||||
gl_view.c \
|
||||
gl_warp.c \
|
||||
gl_vidlinuxglx.c
|
||||
|
||||
|
@ -197,6 +203,8 @@ $(CL_SVGA_name): $(COM_objects) $(CL_objects) $(CL_SW_objects) $(CL_SVGA_objects
|
|||
$(CL_X11_name): $(COM_objects) $(CL_objects) $(CL_SW_objects) $(CL_X11_objects)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ -lm $(CL_X11_libs)
|
||||
|
||||
$(CL_GLX_objects): CPPFLAGS += -I/usr/include/GL
|
||||
|
||||
$(CL_GLX_name): $(COM_objects) $(CL_objects) $(CL_GL_objects) $(CL_GLX_objects)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ -lm $(CL_GLX_libs)
|
||||
|
||||
|
@ -208,7 +216,7 @@ clean:
|
|||
-include $(COM_dependencies)
|
||||
-include $(SV_dependencies)
|
||||
-include $(CL_dependencies)
|
||||
-include $(CL_GL_dependencies)
|
||||
#-include $(CL_GL_dependencies)
|
||||
-include $(CL_SVGA_dependencies)
|
||||
-include $(CL_X11_dependencies)
|
||||
-include $(CL_GLX_dependencies)
|
||||
|
|
606
source/gl_part.c
Normal file
606
source/gl_part.c
Normal file
|
@ -0,0 +1,606 @@
|
|||
/*
|
||||
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$
|
||||
*/
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "glquake.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;
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_InitParticles
|
||||
===============
|
||||
*/
|
||||
void R_InitParticles (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = COM_CheckParm ("-particles");
|
||||
|
||||
if (i)
|
||||
{
|
||||
r_numparticles = (int)(Q_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");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
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)
|
||||
{
|
||||
FILE *f;
|
||||
vec3_t org;
|
||||
int r;
|
||||
int c;
|
||||
particle_t *p;
|
||||
char name[MAX_OSPATH];
|
||||
|
||||
// FIXME sprintf (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 ( ;; )
|
||||
{
|
||||
r = fscanf (f,"%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);
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
Con_Printf ("%i points read\n", c);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
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_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;
|
||||
int scale;
|
||||
|
||||
if (count > 130)
|
||||
scale = 3;
|
||||
else if (count > 20)
|
||||
scale = 2;
|
||||
else
|
||||
scale = 1;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
p->die = cl.time + 0.1*(rand()%5);
|
||||
p->color = (color&~7) + (rand()&7);
|
||||
p->type = pt_grav;
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
p->org[j] = org[j] + scale*((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_grav;
|
||||
|
||||
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_grav;
|
||||
|
||||
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)
|
||||
{
|
||||
vec3_t vec;
|
||||
float len;
|
||||
int j;
|
||||
particle_t *p;
|
||||
|
||||
VectorSubtract (end, start, vec);
|
||||
len = VectorNormalize (vec);
|
||||
while (len > 0)
|
||||
{
|
||||
len -= 3;
|
||||
|
||||
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;
|
||||
|
||||
if (type == 4)
|
||||
{ // slight blood
|
||||
p->type = pt_slowgrav;
|
||||
p->color = 67 + (rand()&3);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
p->org[j] = start[j] + ((rand()%6)-3);
|
||||
len -= 3;
|
||||
}
|
||||
else if (type == 2)
|
||||
{ // blood
|
||||
p->type = pt_slowgrav;
|
||||
p->color = 67 + (rand()&3);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
p->org[j] = start[j] + ((rand()%6)-3);
|
||||
}
|
||||
else if (type == 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);
|
||||
}
|
||||
else if (type == 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);
|
||||
}
|
||||
else if (type == 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);
|
||||
}
|
||||
else if (type == 3 || type == 5)
|
||||
{ // tracer
|
||||
static int tracercount;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
VectorAdd (start, vec, start);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_DrawParticles
|
||||
===============
|
||||
*/
|
||||
void R_DrawParticles (void)
|
||||
{
|
||||
particle_t *p, *kill;
|
||||
float grav;
|
||||
int i;
|
||||
float time2, time3;
|
||||
float time1;
|
||||
float dvel;
|
||||
float frametime;
|
||||
unsigned char *at;
|
||||
unsigned char theAlpha;
|
||||
vec3_t up, right;
|
||||
float scale;
|
||||
qboolean alphaTestEnabled;
|
||||
|
||||
GL_Bind(particletexture);
|
||||
alphaTestEnabled = glIsEnabled(GL_ALPHA_TEST);
|
||||
|
||||
if (alphaTestEnabled)
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glEnable (GL_BLEND);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin (GL_TRIANGLES);
|
||||
|
||||
VectorScale (vup, 1.5, up);
|
||||
VectorScale (vright, 1.5, right);
|
||||
|
||||
frametime = host_frametime;
|
||||
time3 = frametime * 15;
|
||||
time2 = frametime * 10; // 15;
|
||||
time1 = frametime * 5;
|
||||
grav = frametime * 800 * 0.05;
|
||||
dvel = 4*frametime;
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
kill = active_particles;
|
||||
if (kill && kill->die < cl.time)
|
||||
{
|
||||
active_particles = kill->next;
|
||||
kill->next = free_particles;
|
||||
free_particles = kill;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (p=active_particles ; p ; p=p->next)
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
kill = p->next;
|
||||
if (kill && kill->die < cl.time)
|
||||
{
|
||||
p->next = kill->next;
|
||||
kill->next = free_particles;
|
||||
free_particles = kill;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// hack a scale up to keep particles from disapearing
|
||||
scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
|
||||
+ (p->org[2] - r_origin[2])*vpn[2];
|
||||
if (scale < 20)
|
||||
scale = 1;
|
||||
else
|
||||
scale = 1 + scale * 0.004;
|
||||
at = (byte *)&d_8to24table[(int)p->color];
|
||||
if (p->type==pt_fire)
|
||||
theAlpha = 255*(6-p->ramp)/6;
|
||||
// theAlpha = 192;
|
||||
// else if (p->type==pt_explode || p->type==pt_explode2)
|
||||
// theAlpha = 255*(8-p->ramp)/8;
|
||||
else
|
||||
theAlpha = 255;
|
||||
glColor4ub (*at, *(at+1), *(at+2), theAlpha);
|
||||
// glColor3ubv (at);
|
||||
// glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
|
||||
glTexCoord2f (0,0);
|
||||
glVertex3fv (p->org);
|
||||
glTexCoord2f (1,0);
|
||||
glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
|
||||
glTexCoord2f (0,1);
|
||||
glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
|
||||
|
||||
p->org[0] += p->vel[0]*frametime;
|
||||
p->org[1] += p->vel[1]*frametime;
|
||||
p->org[2] += p->vel[2]*frametime;
|
||||
|
||||
switch (p->type)
|
||||
{
|
||||
case pt_static:
|
||||
break;
|
||||
case pt_fire:
|
||||
p->ramp += time1;
|
||||
if (p->ramp >= 6)
|
||||
p->die = -1;
|
||||
else
|
||||
p->color = ramp3[(int)p->ramp];
|
||||
p->vel[2] += grav;
|
||||
break;
|
||||
|
||||
case pt_explode:
|
||||
p->ramp += time2;
|
||||
if (p->ramp >=8)
|
||||
p->die = -1;
|
||||
else
|
||||
p->color = ramp1[(int)p->ramp];
|
||||
for (i=0 ; i<3 ; i++)
|
||||
p->vel[i] += p->vel[i]*dvel;
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
|
||||
case pt_explode2:
|
||||
p->ramp += time3;
|
||||
if (p->ramp >=8)
|
||||
p->die = -1;
|
||||
else
|
||||
p->color = ramp2[(int)p->ramp];
|
||||
for (i=0 ; i<3 ; i++)
|
||||
p->vel[i] -= p->vel[i]*frametime;
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
|
||||
case pt_blob:
|
||||
for (i=0 ; i<3 ; i++)
|
||||
p->vel[i] += p->vel[i]*dvel;
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
|
||||
case pt_blob2:
|
||||
for (i=0 ; i<2 ; i++)
|
||||
p->vel[i] -= p->vel[i]*dvel;
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
|
||||
case pt_slowgrav:
|
||||
case pt_grav:
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glEnd ();
|
||||
glDisable (GL_BLEND);
|
||||
if (alphaTestEnabled)
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
}
|
||||
|
|
@ -67,9 +67,7 @@ cvar_t crosshaircolor = {"crosshaircolor", "79", true};
|
|||
cvar_t cl_crossx = {"cl_crossx", "0", true};
|
||||
cvar_t cl_crossy = {"cl_crossy", "0", true};
|
||||
|
||||
#ifdef GLQUAKE
|
||||
cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false};
|
||||
#endif
|
||||
|
||||
cvar_t v_contentblend = {"v_contentblend", "1", false};
|
||||
|
||||
|
@ -275,10 +273,8 @@ cvar_t v_gamma = {"gamma", "1", true};
|
|||
byte gammatable[256]; // palette is sent through this
|
||||
|
||||
|
||||
#ifdef GLQUAKE
|
||||
byte ramps[3][256];
|
||||
float v_blend[4]; // rgba 0.0 - 1.0
|
||||
#endif // GLQUAKE
|
||||
|
||||
void BuildGammaTable (float g)
|
||||
{
|
||||
|
@ -496,7 +492,6 @@ void V_CalcPowerupCshift (void)
|
|||
V_CalcBlend
|
||||
=============
|
||||
*/
|
||||
#ifdef GLQUAKE
|
||||
void V_CalcBlend (void)
|
||||
{
|
||||
float r, g, b, a, a2;
|
||||
|
@ -534,14 +529,12 @@ void V_CalcBlend (void)
|
|||
if (v_blend[3] < 0)
|
||||
v_blend[3] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
=============
|
||||
V_UpdatePalette
|
||||
=============
|
||||
*/
|
||||
#ifdef GLQUAKE
|
||||
void V_UpdatePalette (void)
|
||||
{
|
||||
int i, j;
|
||||
|
@ -630,81 +623,7 @@ void V_UpdatePalette (void)
|
|||
|
||||
VID_ShiftPalette (pal);
|
||||
}
|
||||
#else // !GLQUAKE
|
||||
/*
|
||||
=============
|
||||
V_UpdatePalette
|
||||
=============
|
||||
*/
|
||||
void V_UpdatePalette (void)
|
||||
{
|
||||
int i, j;
|
||||
qboolean new;
|
||||
byte *basepal, *newpal;
|
||||
byte pal[768];
|
||||
int r,g,b;
|
||||
qboolean force;
|
||||
|
||||
V_CalcPowerupCshift ();
|
||||
|
||||
new = false;
|
||||
|
||||
for (i=0 ; i<NUM_CSHIFTS ; i++)
|
||||
{
|
||||
if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
|
||||
{
|
||||
new = true;
|
||||
cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
|
||||
}
|
||||
for (j=0 ; j<3 ; j++)
|
||||
if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
|
||||
{
|
||||
new = true;
|
||||
cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
|
||||
}
|
||||
}
|
||||
|
||||
// drop the damage value
|
||||
cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
|
||||
if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
|
||||
cl.cshifts[CSHIFT_DAMAGE].percent = 0;
|
||||
|
||||
// drop the bonus value
|
||||
cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
|
||||
if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
|
||||
cl.cshifts[CSHIFT_BONUS].percent = 0;
|
||||
|
||||
force = V_CheckGamma ();
|
||||
if (!new && !force)
|
||||
return;
|
||||
|
||||
basepal = host_basepal;
|
||||
newpal = pal;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
{
|
||||
r = basepal[0];
|
||||
g = basepal[1];
|
||||
b = basepal[2];
|
||||
basepal += 3;
|
||||
|
||||
for (j=0 ; j<NUM_CSHIFTS ; j++)
|
||||
{
|
||||
r += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;
|
||||
g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;
|
||||
b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;
|
||||
}
|
||||
|
||||
newpal[0] = gammatable[r];
|
||||
newpal[1] = gammatable[g];
|
||||
newpal[2] = gammatable[b];
|
||||
newpal += 3;
|
||||
}
|
||||
|
||||
VID_ShiftPalette (pal);
|
||||
}
|
||||
|
||||
#endif // !GLQUAKE
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
@ -1022,10 +941,8 @@ cl.simangles[ROLL] = 0; // FIXME @@@
|
|||
R_PushDlights ();
|
||||
R_RenderView ();
|
||||
|
||||
#ifndef GLQUAKE
|
||||
if (crosshair.value)
|
||||
Draw_Crosshair();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -1059,9 +976,7 @@ void V_Init (void)
|
|||
Cvar_RegisterVariable (&crosshair);
|
||||
Cvar_RegisterVariable (&cl_crossx);
|
||||
Cvar_RegisterVariable (&cl_crossy);
|
||||
#ifdef GLQUAKE
|
||||
Cvar_RegisterVariable (&gl_cshiftpercent);
|
||||
#endif
|
||||
|
||||
Cvar_RegisterVariable (&cl_rollspeed);
|
||||
Cvar_RegisterVariable (&cl_rollangle);
|
|
@ -461,31 +461,11 @@ void R_DrawParticles (void)
|
|||
float time1;
|
||||
float dvel;
|
||||
float frametime;
|
||||
#ifdef GLQUAKE
|
||||
unsigned char *at;
|
||||
unsigned char theAlpha;
|
||||
vec3_t up, right;
|
||||
float scale;
|
||||
qboolean alphaTestEnabled;
|
||||
|
||||
GL_Bind(particletexture);
|
||||
alphaTestEnabled = glIsEnabled(GL_ALPHA_TEST);
|
||||
|
||||
if (alphaTestEnabled)
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glEnable (GL_BLEND);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin (GL_TRIANGLES);
|
||||
|
||||
VectorScale (vup, 1.5, up);
|
||||
VectorScale (vright, 1.5, right);
|
||||
#else
|
||||
D_StartParticles ();
|
||||
|
||||
VectorScale (vright, xscaleshrink, r_pright);
|
||||
VectorScale (vup, yscaleshrink, r_pup);
|
||||
VectorCopy (vpn, r_ppn);
|
||||
#endif
|
||||
|
||||
frametime = host_frametime;
|
||||
time3 = frametime * 15;
|
||||
|
@ -522,35 +502,7 @@ void R_DrawParticles (void)
|
|||
break;
|
||||
}
|
||||
|
||||
#ifdef GLQUAKE
|
||||
// hack a scale up to keep particles from disapearing
|
||||
scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
|
||||
+ (p->org[2] - r_origin[2])*vpn[2];
|
||||
if (scale < 20)
|
||||
scale = 1;
|
||||
else
|
||||
scale = 1 + scale * 0.004;
|
||||
at = (byte *)&d_8to24table[(int)p->color];
|
||||
if (p->type==pt_fire)
|
||||
theAlpha = 255*(6-p->ramp)/6;
|
||||
// theAlpha = 192;
|
||||
// else if (p->type==pt_explode || p->type==pt_explode2)
|
||||
// theAlpha = 255*(8-p->ramp)/8;
|
||||
else
|
||||
theAlpha = 255;
|
||||
glColor4ub (*at, *(at+1), *(at+2), theAlpha);
|
||||
// glColor3ubv (at);
|
||||
// glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
|
||||
glTexCoord2f (0,0);
|
||||
glVertex3fv (p->org);
|
||||
glTexCoord2f (1,0);
|
||||
glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
|
||||
glTexCoord2f (0,1);
|
||||
glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
|
||||
|
||||
#else
|
||||
D_DrawParticle (p);
|
||||
#endif
|
||||
|
||||
p->org[0] += p->vel[0]*frametime;
|
||||
p->org[1] += p->vel[1]*frametime;
|
||||
|
@ -610,14 +562,6 @@ void R_DrawParticles (void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef GLQUAKE
|
||||
glEnd ();
|
||||
glDisable (GL_BLEND);
|
||||
if (alphaTestEnabled)
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
#else
|
||||
D_EndParticles ();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
921
source/r_view.c
Normal file
921
source/r_view.c
Normal file
|
@ -0,0 +1,921 @@
|
|||
/*
|
||||
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$
|
||||
*/
|
||||
// view.c -- player eye positioning
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "r_local.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 lcd_x = {"lcd_x", "0"}; // FIXME: make this work sometime...
|
||||
|
||||
cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
|
||||
cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
|
||||
|
||||
cvar_t cl_bob = {"cl_bob","0.02", false};
|
||||
cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false};
|
||||
cvar_t cl_bobup = {"cl_bobup","0.5", false};
|
||||
|
||||
cvar_t v_kicktime = {"v_kicktime", "0.5", false};
|
||||
cvar_t v_kickroll = {"v_kickroll", "0.6", false};
|
||||
cvar_t v_kickpitch = {"v_kickpitch", "0.6", false};
|
||||
|
||||
cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false};
|
||||
cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false};
|
||||
cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false};
|
||||
cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false};
|
||||
cvar_t v_iroll_level = {"v_iroll_level", "0.1", false};
|
||||
cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false};
|
||||
|
||||
cvar_t v_idlescale = {"v_idlescale", "0", false};
|
||||
|
||||
cvar_t crosshair = {"crosshair", "0", true};
|
||||
cvar_t crosshaircolor = {"crosshaircolor", "79", true};
|
||||
|
||||
cvar_t cl_crossx = {"cl_crossx", "0", true};
|
||||
cvar_t cl_crossy = {"cl_crossy", "0", true};
|
||||
|
||||
cvar_t v_contentblend = {"v_contentblend", "1", false};
|
||||
|
||||
float v_dmg_time, v_dmg_roll, v_dmg_pitch;
|
||||
|
||||
extern int in_forward, in_forward2, in_back;
|
||||
|
||||
frame_t *view_frame;
|
||||
player_state_t *view_message;
|
||||
|
||||
/*
|
||||
===============
|
||||
V_CalcRoll
|
||||
|
||||
===============
|
||||
*/
|
||||
float V_CalcRoll (vec3_t angles, vec3_t velocity)
|
||||
{
|
||||
vec3_t forward, right, up;
|
||||
float sign;
|
||||
float side;
|
||||
float value;
|
||||
|
||||
AngleVectors (angles, forward, right, up);
|
||||
side = DotProduct (velocity, right);
|
||||
sign = side < 0 ? -1 : 1;
|
||||
side = fabs(side);
|
||||
|
||||
value = cl_rollangle.value;
|
||||
|
||||
if (side < cl_rollspeed.value)
|
||||
side = side * value / cl_rollspeed.value;
|
||||
else
|
||||
side = value;
|
||||
|
||||
return side*sign;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
V_CalcBob
|
||||
|
||||
===============
|
||||
*/
|
||||
float V_CalcBob (void)
|
||||
{
|
||||
static double bobtime;
|
||||
static float bob;
|
||||
float cycle;
|
||||
|
||||
if (cl.spectator)
|
||||
return 0;
|
||||
|
||||
if (onground == -1)
|
||||
return bob; // just use old value
|
||||
|
||||
bobtime += host_frametime;
|
||||
cycle = bobtime - (int)(bobtime/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 simulated velocity in the xy plane
|
||||
// (don't count Z, or jumping messes it up)
|
||||
|
||||
bob = sqrt(cl.simvel[0]*cl.simvel[0] + cl.simvel[1]*cl.simvel[1]) * cl_bob.value;
|
||||
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 = {"v_centermove", "0.15", false};
|
||||
cvar_t v_centerspeed = {"v_centerspeed","500"};
|
||||
|
||||
|
||||
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 (view_message->onground == -1 || cls.demoplayback )
|
||||
{
|
||||
cl.driftmove = 0;
|
||||
cl.pitchvel = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// don't count small mouse motion
|
||||
if (cl.nodrift)
|
||||
{
|
||||
if ( fabs(cl.frames[(cls.netchan.outgoing_sequence-1)&UPDATE_MASK].cmd.forwardmove) < 200)
|
||||
cl.driftmove = 0;
|
||||
else
|
||||
cl.driftmove += host_frametime;
|
||||
|
||||
if ( cl.driftmove > v_centermove.value)
|
||||
{
|
||||
V_StartPitchDrift ();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
delta = 0 - 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 = {"gamma", "1", true};
|
||||
|
||||
byte gammatable[256]; // palette is sent through this
|
||||
|
||||
|
||||
void BuildGammaTable (float g)
|
||||
{
|
||||
int i, inf;
|
||||
|
||||
if (g == 1.0)
|
||||
{
|
||||
for (i=0 ; i<256 ; i++)
|
||||
gammatable[i] = i;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
{
|
||||
inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
|
||||
if (inf < 0)
|
||||
inf = 0;
|
||||
if (inf > 255)
|
||||
inf = 255;
|
||||
gammatable[i] = inf;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
V_CheckGamma
|
||||
=================
|
||||
*/
|
||||
qboolean V_CheckGamma (void)
|
||||
{
|
||||
static float oldgammavalue;
|
||||
|
||||
if (v_gamma.value == oldgammavalue)
|
||||
return false;
|
||||
oldgammavalue = v_gamma.value;
|
||||
|
||||
BuildGammaTable (v_gamma.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;
|
||||
float side;
|
||||
float count;
|
||||
|
||||
armor = MSG_ReadByte ();
|
||||
blood = MSG_ReadByte ();
|
||||
for (i=0 ; i<3 ; i++)
|
||||
from[i] = MSG_ReadCoord ();
|
||||
|
||||
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
|
||||
//
|
||||
VectorSubtract (from, cl.simorg, from);
|
||||
VectorNormalize (from);
|
||||
|
||||
AngleVectors (cl.simangles, 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)
|
||||
{
|
||||
if (!v_contentblend.value) {
|
||||
cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (contents)
|
||||
{
|
||||
case CONTENTS_EMPTY:
|
||||
cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
|
||||
break;
|
||||
case CONTENTS_LAVA:
|
||||
cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
|
||||
break;
|
||||
case CONTENTS_SOLID:
|
||||
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.stats[STAT_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.stats[STAT_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.stats[STAT_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.stats[STAT_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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
V_UpdatePalette
|
||||
=============
|
||||
*/
|
||||
void V_UpdatePalette (void)
|
||||
{
|
||||
int i, j;
|
||||
qboolean new;
|
||||
byte *basepal, *newpal;
|
||||
byte pal[768];
|
||||
int r,g,b;
|
||||
qboolean force;
|
||||
|
||||
V_CalcPowerupCshift ();
|
||||
|
||||
new = false;
|
||||
|
||||
for (i=0 ; i<NUM_CSHIFTS ; i++)
|
||||
{
|
||||
if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
|
||||
{
|
||||
new = true;
|
||||
cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
|
||||
}
|
||||
for (j=0 ; j<3 ; j++)
|
||||
if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
|
||||
{
|
||||
new = true;
|
||||
cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
|
||||
}
|
||||
}
|
||||
|
||||
// drop the damage value
|
||||
cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
|
||||
if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
|
||||
cl.cshifts[CSHIFT_DAMAGE].percent = 0;
|
||||
|
||||
// drop the bonus value
|
||||
cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
|
||||
if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
|
||||
cl.cshifts[CSHIFT_BONUS].percent = 0;
|
||||
|
||||
force = V_CheckGamma ();
|
||||
if (!new && !force)
|
||||
return;
|
||||
|
||||
basepal = host_basepal;
|
||||
newpal = pal;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
{
|
||||
r = basepal[0];
|
||||
g = basepal[1];
|
||||
b = basepal[2];
|
||||
basepal += 3;
|
||||
|
||||
for (j=0 ; j<NUM_CSHIFTS ; j++)
|
||||
{
|
||||
r += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;
|
||||
g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;
|
||||
b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;
|
||||
}
|
||||
|
||||
newpal[0] = gammatable[r];
|
||||
newpal[1] = gammatable[g];
|
||||
newpal[2] = gammatable[b];
|
||||
newpal += 3;
|
||||
}
|
||||
|
||||
VID_ShiftPalette (pal);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
V_BoundOffsets
|
||||
==============
|
||||
*/
|
||||
void V_BoundOffsets (void)
|
||||
{
|
||||
// absolutely bound refresh reletive to entity clipping hull
|
||||
// so the view can never be inside a solid wall
|
||||
|
||||
if (r_refdef.vieworg[0] < cl.simorg[0] - 14)
|
||||
r_refdef.vieworg[0] = cl.simorg[0] - 14;
|
||||
else if (r_refdef.vieworg[0] > cl.simorg[0] + 14)
|
||||
r_refdef.vieworg[0] = cl.simorg[0] + 14;
|
||||
if (r_refdef.vieworg[1] < cl.simorg[1] - 14)
|
||||
r_refdef.vieworg[1] = cl.simorg[1] - 14;
|
||||
else if (r_refdef.vieworg[1] > cl.simorg[1] + 14)
|
||||
r_refdef.vieworg[1] = cl.simorg[1] + 14;
|
||||
if (r_refdef.vieworg[2] < cl.simorg[2] - 22)
|
||||
r_refdef.vieworg[2] = cl.simorg[2] - 22;
|
||||
else if (r_refdef.vieworg[2] > cl.simorg[2] + 30)
|
||||
r_refdef.vieworg[2] = cl.simorg[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;
|
||||
|
||||
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_CalcViewRoll
|
||||
|
||||
Roll is induced by movement and damage
|
||||
==============
|
||||
*/
|
||||
void V_CalcViewRoll (void)
|
||||
{
|
||||
float side;
|
||||
|
||||
side = V_CalcRoll (cl.simangles, cl.simvel);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
V_CalcIntermissionRefdef
|
||||
|
||||
==================
|
||||
*/
|
||||
void V_CalcIntermissionRefdef (void)
|
||||
{
|
||||
entity_t *view;
|
||||
float old;
|
||||
|
||||
// view is the weapon model
|
||||
view = &cl.viewent;
|
||||
|
||||
VectorCopy (cl.simorg, r_refdef.vieworg);
|
||||
VectorCopy (cl.simangles, r_refdef.viewangles);
|
||||
view->model = NULL;
|
||||
|
||||
// allways idle in intermission
|
||||
old = v_idlescale.value;
|
||||
v_idlescale.value = 1;
|
||||
V_AddIdle ();
|
||||
v_idlescale.value = old;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
V_CalcRefdef
|
||||
|
||||
==================
|
||||
*/
|
||||
void V_CalcRefdef (void)
|
||||
{
|
||||
entity_t *view;
|
||||
int i;
|
||||
vec3_t forward, right, up;
|
||||
float bob;
|
||||
static float oldz = 0;
|
||||
|
||||
V_DriftPitch ();
|
||||
|
||||
// view is the weapon model (only visible from inside body)
|
||||
view = &cl.viewent;
|
||||
|
||||
bob = V_CalcBob ();
|
||||
|
||||
// refresh position from simulated origin
|
||||
VectorCopy (cl.simorg, r_refdef.vieworg);
|
||||
|
||||
r_refdef.vieworg[2] += 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/8 pixel, so add 1/16 in each axis
|
||||
r_refdef.vieworg[0] += 1.0/16;
|
||||
r_refdef.vieworg[1] += 1.0/16;
|
||||
r_refdef.vieworg[2] += 1.0/16;
|
||||
|
||||
VectorCopy (cl.simangles, r_refdef.viewangles);
|
||||
V_CalcViewRoll ();
|
||||
V_AddIdle ();
|
||||
|
||||
if (view_message->flags & PF_GIB)
|
||||
r_refdef.vieworg[2] += 8; // gib view height
|
||||
else if (view_message->flags & PF_DEAD)
|
||||
r_refdef.vieworg[2] -= 16; // corpse view height
|
||||
else
|
||||
r_refdef.vieworg[2] += 22; // view height
|
||||
|
||||
if (view_message->flags & PF_DEAD) // PF_GIB will also set PF_DEAD
|
||||
r_refdef.viewangles[ROLL] = 80; // dead view angle
|
||||
|
||||
|
||||
// offsets
|
||||
AngleVectors (cl.simangles, forward, right, up);
|
||||
|
||||
// set up gun position
|
||||
VectorCopy (cl.simangles, view->angles);
|
||||
|
||||
CalcGunAngle ();
|
||||
|
||||
VectorCopy (cl.simorg, view->origin);
|
||||
view->origin[2] += 22;
|
||||
|
||||
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 (scr_viewsize.value == 110)
|
||||
view->origin[2] += 1;
|
||||
else if (scr_viewsize.value == 100)
|
||||
view->origin[2] += 2;
|
||||
else if (scr_viewsize.value == 90)
|
||||
view->origin[2] += 1;
|
||||
else if (scr_viewsize.value == 80)
|
||||
view->origin[2] += 0.5;
|
||||
|
||||
if (view_message->flags & (PF_GIB|PF_DEAD) )
|
||||
view->model = NULL;
|
||||
else
|
||||
view->model = cl.model_precache[cl.stats[STAT_WEAPON]];
|
||||
view->frame = view_message->weaponframe;
|
||||
view->colormap = vid.colormap;
|
||||
|
||||
// set up the refresh position
|
||||
r_refdef.viewangles[PITCH] += cl.punchangle;
|
||||
|
||||
// smooth out stair step ups
|
||||
if ( (view_message->onground != -1) && (cl.simorg[2] - oldz > 0) )
|
||||
{
|
||||
float steptime;
|
||||
|
||||
steptime = host_frametime;
|
||||
|
||||
oldz += steptime * 80;
|
||||
if (oldz > cl.simorg[2])
|
||||
oldz = cl.simorg[2];
|
||||
if (cl.simorg[2] - oldz > 12)
|
||||
oldz = cl.simorg[2] - 12;
|
||||
r_refdef.vieworg[2] += oldz - cl.simorg[2];
|
||||
view->origin[2] += oldz - cl.simorg[2];
|
||||
}
|
||||
else
|
||||
oldz = cl.simorg[2];
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
DropPunchAngle
|
||||
=============
|
||||
*/
|
||||
void DropPunchAngle (void)
|
||||
{
|
||||
cl.punchangle -= 10*host_frametime;
|
||||
if (cl.punchangle < 0)
|
||||
cl.punchangle = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
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;
|
||||
|
||||
void V_RenderView (void)
|
||||
{
|
||||
// if (cl.simangles[ROLL])
|
||||
// Sys_Error ("cl.simangles[ROLL]"); // DEBUG
|
||||
cl.simangles[ROLL] = 0; // FIXME @@@
|
||||
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
view_frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
|
||||
view_message = &view_frame->playerstate[cl.playernum];
|
||||
|
||||
DropPunchAngle ();
|
||||
if (cl.intermission)
|
||||
{ // intermission / finale rendering
|
||||
V_CalcIntermissionRefdef ();
|
||||
}
|
||||
else
|
||||
{
|
||||
V_CalcRefdef ();
|
||||
}
|
||||
|
||||
R_PushDlights ();
|
||||
R_RenderView ();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
V_Init
|
||||
=============
|
||||
*/
|
||||
void V_Init (void)
|
||||
{
|
||||
Cmd_AddCommand ("v_cshift", V_cshift_f);
|
||||
Cmd_AddCommand ("bf", V_BonusFlash_f);
|
||||
Cmd_AddCommand ("centerview", V_StartPitchDrift);
|
||||
|
||||
Cvar_RegisterVariable (&v_centermove);
|
||||
Cvar_RegisterVariable (&v_centerspeed);
|
||||
|
||||
Cvar_RegisterVariable (&v_iyaw_cycle);
|
||||
Cvar_RegisterVariable (&v_iroll_cycle);
|
||||
Cvar_RegisterVariable (&v_ipitch_cycle);
|
||||
Cvar_RegisterVariable (&v_iyaw_level);
|
||||
Cvar_RegisterVariable (&v_iroll_level);
|
||||
Cvar_RegisterVariable (&v_ipitch_level);
|
||||
|
||||
Cvar_RegisterVariable (&v_contentblend);
|
||||
|
||||
Cvar_RegisterVariable (&v_idlescale);
|
||||
Cvar_RegisterVariable (&crosshaircolor);
|
||||
Cvar_RegisterVariable (&crosshair);
|
||||
Cvar_RegisterVariable (&cl_crossx);
|
||||
Cvar_RegisterVariable (&cl_crossy);
|
||||
|
||||
Cvar_RegisterVariable (&cl_rollspeed);
|
||||
Cvar_RegisterVariable (&cl_rollangle);
|
||||
Cvar_RegisterVariable (&cl_bob);
|
||||
Cvar_RegisterVariable (&cl_bobcycle);
|
||||
Cvar_RegisterVariable (&cl_bobup);
|
||||
|
||||
Cvar_RegisterVariable (&v_kicktime);
|
||||
Cvar_RegisterVariable (&v_kickroll);
|
||||
Cvar_RegisterVariable (&v_kickpitch);
|
||||
|
||||
BuildGammaTable (1.0); // no gamma yet
|
||||
Cvar_RegisterVariable (&v_gamma);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in a new issue