/* gl_dyn_part.c OpenGL particle system. 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 */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/mersenne.h" #include "QF/qargs.h" #include "QF/quakefs.h" #include "QF/render.h" #include "QF/sys.h" #include "QF/va.h" #include "QF/scene/entity.h" #include "QF/GL/defines.h" #include "QF/GL/funcs.h" #include "QF/GL/qf_particles.h" #include "QF/GL/qf_textures.h" #include "QF/GL/qf_vid.h" #include "compat.h" #include "r_internal.h" #include "varrays.h" static int partUseVA; static int pVAsize; static int *pVAindices; static varray_t2f_c4ub_v3f_t *particleVertexArray; static void alloc_arrays (psystem_t *ps) { int i; if (ps->maxparticles && r_init) { if (vaelements) { partUseVA = 0; pVAsize = ps->maxparticles * 4; Sys_MaskPrintf (SYS_dev, "Particles: Vertex Array use disabled.\n"); } else { if (vaelements > 3) pVAsize = min ((unsigned int) (vaelements - (vaelements % 4)), ps->maxparticles * 4); else if (vaelements >= 0) pVAsize = ps->maxparticles * 4; Sys_MaskPrintf (SYS_dev, "Particles: %i maximum vertex elements.\n", pVAsize); } if (particleVertexArray) free (particleVertexArray); particleVertexArray = (varray_t2f_c4ub_v3f_t *) calloc (pVAsize, sizeof (varray_t2f_c4ub_v3f_t)); if (partUseVA) qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, particleVertexArray); if (pVAindices) free (pVAindices); pVAindices = (int *) calloc (pVAsize, sizeof (int)); for (i = 0; i < pVAsize; i++) pVAindices[i] = i; } else { if (particleVertexArray) { free (particleVertexArray); particleVertexArray = 0; } if (pVAindices) { free (pVAindices); pVAindices = 0; } } } static void gl_particles_f (void *data, const cvar_t *cvar) { alloc_arrays (&r_psystem);//FIXME } void gl_R_InitParticles (void) { Cvar_AddListener (Cvar_FindVar ("r_particles"), gl_particles_f, 0); Cvar_AddListener (Cvar_FindVar ("r_particles_max"), gl_particles_f, 0); alloc_arrays (&r_psystem); } void gl_R_DrawParticles (psystem_t *psystem) { unsigned char *at; int vacount; float minparticledist, scale; vec3_t up_scale, right_scale, up_right_scale, down_right_scale; varray_t2f_c4ub_v3f_t *VA; if (!r_psystem.numparticles) { return; } qfglBindTexture (GL_TEXTURE_2D, gl_part_tex); // LordHavoc: particles should not affect zbuffer qfglDepthMask (GL_FALSE); qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, particleVertexArray); minparticledist = DotProduct (r_refdef.frame.position, r_refdef.frame.forward) + r_particles_nearclip; vacount = 0; VA = particleVertexArray; for (unsigned i = 0; i < r_psystem.numparticles; i++) { particle_t *p = &r_psystem.particles[i]; // Don't render particles too close to us. // Note, we must still do physics and such on them. if (!(DotProduct (p->pos, r_refdef.frame.forward) < minparticledist)) { at = (byte *) &d_8to24table[(byte) p->icolor]; VA[0].color[0] = at[0]; VA[0].color[1] = at[1]; VA[0].color[2] = at[2]; VA[0].color[3] = p->alpha * 255; memcpy (VA[1].color, VA[0].color, sizeof (VA[0].color)); memcpy (VA[2].color, VA[0].color, sizeof (VA[0].color)); memcpy (VA[3].color, VA[0].color, sizeof (VA[0].color)); switch (p->tex) { case part_tex_dot: VA[0].texcoord[0] = 0.0; VA[0].texcoord[1] = 0.0; VA[1].texcoord[0] = 0.5; VA[1].texcoord[1] = 0.0; VA[2].texcoord[0] = 0.5; VA[2].texcoord[1] = 0.5; VA[3].texcoord[0] = 0.0; VA[3].texcoord[1] = 0.5; break; case part_tex_spark: VA[0].texcoord[0] = 0.5; VA[0].texcoord[1] = 0.0; VA[1].texcoord[0] = 1.0; VA[1].texcoord[1] = 0.0; VA[2].texcoord[0] = 1.0; VA[2].texcoord[1] = 0.5; VA[3].texcoord[0] = 0.5; VA[3].texcoord[1] = 0.5; break; case part_tex_smoke: VA[0].texcoord[0] = 0.0; VA[0].texcoord[1] = 0.5; VA[1].texcoord[0] = 0.5; VA[1].texcoord[1] = 0.5; VA[2].texcoord[0] = 0.5; VA[2].texcoord[1] = 1.0; VA[3].texcoord[0] = 0.0; VA[3].texcoord[1] = 1.0; break; } scale = p->scale; VectorScale (r_refdef.frame.up, scale, up_scale); VectorScale (r_refdef.frame.right, scale, right_scale); VectorAdd (right_scale, up_scale, up_right_scale); VectorSubtract (right_scale, up_scale, down_right_scale); VectorAdd (p->pos, down_right_scale, VA[0].vertex); VectorSubtract (p->pos, up_right_scale, VA[1].vertex); VectorSubtract (p->pos, down_right_scale, VA[2].vertex); VectorAdd (p->pos, up_right_scale, VA[3].vertex); VA += 4; vacount += 4; if (vacount + 4 > pVAsize) { // never reached if partUseVA is false qfglDrawElements (GL_QUADS, vacount, GL_UNSIGNED_INT, pVAindices); vacount = 0; VA = particleVertexArray; } } } if (vacount) { if (partUseVA) { qfglDrawElements (GL_QUADS, vacount, GL_UNSIGNED_INT, pVAindices); } else { varray_t2f_c4ub_v3f_t *va = particleVertexArray; int i; qfglBegin (GL_QUADS); for (i = 0; i < vacount; i++, va++) { qfglTexCoord2fv (va->texcoord); qfglColor4ubv (va->color); qfglVertex3fv (va->vertex); } qfglEnd (); } } qfglColor3ubv (color_white); qfglDepthMask (GL_TRUE); } psystem_t * __attribute__((const))//FIXME gl_ParticleSystem (void) { return &r_psystem; }