mirror of
https://git.code.sf.net/p/quake/newtree
synced 2024-11-29 15:23:02 +00:00
8d08bc4d86
make work properly: Win32 thing.. If you don't free textures explicitly, you can cause a problem with nVidia drivers. Colored lighting is now RGB instead of RGBA. The alpha is kinda pointless on a lightmap and the effect's not all that great. Plus people stuck with 16 bit OpenGL (any other 3dfx people out there?) will be quite pleased with the improvement in image quality. This does include LordHavoc's dynamic light optimization code which takes most of the pain out of having gl_flashblend off. All glColor*'s are now half of what they used to be, except where they aren't. If that doesn't make sense, don't worry. If you see one that's only half what you'd expect, don't worry---it probably is meant to be like that.. (More below) glDisable (GL_BLEND) is now a thing of the GL_PAST. As is GL_REPLACE. Instead, we _always_ use GL_MODULATE and leave GL_BLEND turned on. This seems at first like it might be a performance hit, but I swear it's much more expensive to change blending modes and texture functions 20-30 times every screen frame! Win32 issue.. Even though we check for multitexture, we currently don't use it. Reason is that I am planning to replace SGIS_multitexture with the preferred ARB_multitexture extension which is supported in most GL 1.1 implementations and is a requirement for GL 1.2 anyway. I also wanted to get rid of some duplicated code. Since Linux doesn't support multitexture yet, I just commented out the code keeping me from compiling to get it to work. Win32 should work without it until it's fixed, which shouldn't be long since the differences between SGIS and ARB multitextures as far as Quake is concerned is minimal AT BEST. LordHavoc and I have been working tirelessly (well not quite, we both did manage to sleep sometime during this ordeal) to fix the lighting in the GL renderers! It looks DAMNED CLOSE to software's lighting now, including the ability to overbright a color. You've gotta see this to know what I'm talking about. That's why the glColor*'s are halved in most places. The gamma table code and the general way it works is LordHavoc's design, but over the course of re-implementing it in QF we did come up with a few more small optimizations. A lot of people have noticed that QF's fps count has gone to shit lately. No promises that this undid whatever the problem was. That means there could be a huge optimization lurking somewhere in the shadows, waiting for us to fix it for a massive FPS boost. Even if there's not, the code in this commit DOUBLED MY FPS COUNT. Granted I was getting pathetic FPS as it was (around 30, which is pathetic even for a Voodoo3 in Linux) but still---60 is a big improvement over 30! Please be sure to "test" this code thuroughly.
629 lines
12 KiB
C
629 lines
12 KiB
C
/*
|
|
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 "qargs.h"
|
|
#include "bothdefs.h" // needed by: common.h, net.h, client.h
|
|
#include "d_iface.h"
|
|
#include "bspfile.h" // needed by: glquake.h
|
|
#include "vid.h"
|
|
#include "sys.h"
|
|
#include "zone.h" // needed by: client.h, gl_model.h
|
|
#include "mathlib.h" // needed by: protocol.h, render.h, client.h,
|
|
// modelgen.h, glmodel.h
|
|
#include "wad.h"
|
|
#include "draw.h"
|
|
#include "cvar.h"
|
|
#include "menu.h"
|
|
#include "net.h" // needed by: client.h
|
|
#include "protocol.h" // needed by: client.h
|
|
#include "cmd.h"
|
|
#include "sbar.h"
|
|
#include "render.h" // needed by: client.h, gl_model.h, glquake.h
|
|
#include "client.h" // need cls in this file
|
|
#include "model.h" // needed by: glquake.h
|
|
#include "console.h"
|
|
#include "glquake.h"
|
|
#include "quakefs.h"
|
|
#include "quakedef.h"
|
|
|
|
#include <stdlib.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)(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);
|
|
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 ();
|
|
if (alphaTestEnabled)
|
|
glEnable(GL_ALPHA_TEST);
|
|
}
|
|
|