summaryrefslogtreecommitdiff
path: root/source/sw_part.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/sw_part.c')
-rw-r--r--source/sw_part.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/source/sw_part.c b/source/sw_part.c
new file mode 100644
index 0000000..c3fb2ce
--- /dev/null
+++ b/source/sw_part.c
@@ -0,0 +1,191 @@
+/*
+Copyright (C) 1997-2001 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 the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+#include "sw_local.h"
+
+vec3_t r_pright, r_pup, r_ppn;
+
+#define PARTICLE_33 0
+#define PARTICLE_66 1
+#define PARTICLE_OPAQUE 2
+
+typedef struct
+{
+ particle_t *particle;
+ int level;
+ int color;
+} partparms_t;
+
+static partparms_t partparms;
+
+/*
+** R_DrawParticle
+**
+** Yes, this is amazingly slow, but it's the C reference
+** implementation and should be both robust and vaguely
+** understandable. The only time this path should be
+** executed is if we're debugging on x86 or if we're
+** recompiling and deploying on a non-x86 platform.
+**
+** To minimize error and improve readability I went the
+** function pointer route. This exacts some overhead, but
+** it pays off in clean and easy to understand code.
+*/
+static void R_DrawParticle( void )
+{
+ particle_t *pparticle = partparms.particle;
+ int level = partparms.level;
+ vec3_t local, transformed;
+ float zi;
+ byte *pdest;
+ short *pz;
+ int color = pparticle->color;
+ int i, izi, pix, count, u, v;
+
+ /*
+ ** transform the particle
+ */
+ VectorSubtract (pparticle->origin, r_origin, local);
+
+ transformed[0] = DotProduct(local, r_pright);
+ transformed[1] = DotProduct(local, r_pup);
+ transformed[2] = DotProduct(local, r_ppn);
+
+ if (transformed[2] < PARTICLE_Z_CLIP)
+ return;
+
+ /*
+ ** project the point
+ */
+ // FIXME: preadjust xcenter and ycenter
+ zi = 1.0 / transformed[2];
+ u = (int)(xcenter + zi * transformed[0] + 0.5);
+ v = (int)(ycenter - zi * transformed[1] + 0.5);
+
+ if ((v > d_vrectbottom_particle) ||
+ (u > d_vrectright_particle) ||
+ (v < d_vrecty) ||
+ (u < d_vrectx))
+ {
+ return;
+ }
+
+ /*
+ ** compute addresses of zbuffer, framebuffer, and
+ ** compute the Z-buffer reference value.
+ */
+ pz = d_pzbuffer + (d_zwidth * v) + u;
+ pdest = d_viewbuffer + d_scantable[v] + u;
+ izi = (int)(zi * 0x8000);
+
+ /*
+ ** determine the screen area covered by the particle,
+ ** which also means clamping to a min and max
+ */
+ pix = izi >> d_pix_shift;
+ if (pix < d_pix_min)
+ pix = d_pix_min;
+ else if (pix > d_pix_max)
+ pix = d_pix_max;
+
+ /*
+ ** render the appropriate pixels
+ */
+ count = pix;
+
+ switch (level) {
+ case PARTICLE_33 :
+ for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+ {
+//FIXME--do it in blocks of 8?
+ for (i=0 ; i<pix ; i++)
+ {
+ if (pz[i] <= izi)
+ {
+ pz[i] = izi;
+ pdest[i] = vid.alphamap[color + ((int)pdest[i]<<8)];
+ }
+ }
+ }
+ break;
+
+ case PARTICLE_66 :
+ for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+ {
+ for (i=0 ; i<pix ; i++)
+ {
+ if (pz[i] <= izi)
+ {
+ pz[i] = izi;
+ pdest[i] = vid.alphamap[(color<<8) + (int)pdest[i]];
+ }
+ }
+ }
+ break;
+
+ default: //100
+ for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+ {
+ for (i=0 ; i<pix ; i++)
+ {
+ if (pz[i] <= izi)
+ {
+ pz[i] = izi;
+ pdest[i] = color;
+ }
+ }
+ }
+ break;
+ }
+}
+
+/*
+** R_DrawParticles
+**
+** Responsible for drawing all of the particles in the particle list
+** throughout the world. Doesn't care if we're using the C path or
+** if we're using the asm path, it simply assigns a function pointer
+** and goes.
+*/
+void R_DrawParticles (void)
+{
+ particle_t *p;
+ int i;
+
+ VectorScale( vright, xscaleshrink, r_pright );
+ VectorScale( vup, yscaleshrink, r_pup );
+ VectorCopy( vpn, r_ppn );
+
+ for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
+ {
+
+ if ( p->alpha > 0.66 )
+ partparms.level = PARTICLE_OPAQUE;
+ else if ( p->alpha > 0.33 )
+ partparms.level = PARTICLE_66;
+ else
+ partparms.level = PARTICLE_33;
+
+ partparms.particle = p;
+ partparms.color = p->color;
+
+ R_DrawParticle();
+ }
+}
+