From b2c8a70b71f9e8cc3f615af7254e82c32ae2541d Mon Sep 17 00:00:00 2001 From: skyjake Date: Fri, 28 Feb 2003 10:42:15 +0000 Subject: [PATCH] Added textured particles, planeflat sticks to planes --- doomsday/Include/gl_tex.h | 2 + doomsday/Include/p_particle.h | 7 +- doomsday/Src/gl_tex.c | 3 + doomsday/Src/p_particle.c | 90 +++++++++++++++------- doomsday/Src/rend_particle.c | 140 +++++++++++++++++++++++++++++----- 5 files changed, 194 insertions(+), 48 deletions(-) diff --git a/doomsday/Include/gl_tex.h b/doomsday/Include/gl_tex.h index 231f6e5b16..e5035c56c0 100644 --- a/doomsday/Include/gl_tex.h +++ b/doomsday/Include/gl_tex.h @@ -40,6 +40,8 @@ byte * GL_LoadImage(const char *imagefn, int *width, int *height, int *pixsize, boolean *masked, boolean usemodelpath); byte * GL_LoadImageCK(const char *imagefn, int *width, int *height, int *pixsize, boolean *masked, boolean usemodelpath); +byte * GL_LoadHighResTexture(char *name, int *width, int *height, + int *pixsize, boolean *masked); DGLuint GL_PrepareTexture(int idx); DGLuint GL_PrepareFlat(int idx); DGLuint GL_PrepareLightTexture(void); // The dynamic light map. diff --git a/doomsday/Include/p_particle.h b/doomsday/Include/p_particle.h index 746e8cd7e8..1459827594 100644 --- a/doomsday/Include/p_particle.h +++ b/doomsday/Include/p_particle.h @@ -3,6 +3,7 @@ #define MAX_ACTIVE_PTCGENS 96 #define MAX_PTC_STAGES DED_PTC_STAGES +#define MAX_PTC_TEXTURES 32 // Maximum # of textures in particle system // Generator flags #define PGF_STATIC 0x1 // Can't be replaced by anything. @@ -26,7 +27,10 @@ enum { PTC_NONE, PTC_POINT, - PTC_LINE + PTC_LINE, + // New types can be added here. + PTC_TEXTURE = 100 + // ...followed by MAX_PTC_TEXTURES types. } ptc_type_e; // Particle flags @@ -92,5 +96,6 @@ void P_SpawnDamageParticleGen(mobj_t *mo, mobj_t *inflictor, int amount); void P_CheckPtcPlanes(void); float P_GetParticleRadius(ded_ptcstage_t *stage_def, int ptc_index); +fixed_t P_GetParticleZ(particle_t *pt); #endif \ No newline at end of file diff --git a/doomsday/Src/gl_tex.c b/doomsday/Src/gl_tex.c index 2c94d736a4..c4fb98dbdc 100644 --- a/doomsday/Src/gl_tex.c +++ b/doomsday/Src/gl_tex.c @@ -1534,6 +1534,7 @@ byte *GL_LoadHighRes(char *name, char *path, char *altPath, char *prefix, //=========================================================================== // GL_LoadHighResTexture +// The returned buffer must be freed with M_Free. //=========================================================================== byte *GL_LoadHighResTexture (char *name, int *width, int *height, int *pixsize, boolean *masked) @@ -1544,11 +1545,13 @@ byte *GL_LoadHighResTexture //=========================================================================== // GL_LoadHighResFlat +// The returned buffer must be freed with M_Free. //=========================================================================== byte *GL_LoadHighResFlat(char *name, int *width, int *height, int *pixsize) { boolean masked; + // FIXME: Why no subdir named "Flats"? return GL_LoadHighRes(name, hiTexPath, hiTexPath2, "Flat-", width, height, pixsize, &masked, false); } diff --git a/doomsday/Src/p_particle.c b/doomsday/Src/p_particle.c index 0c3c4eaada..882a08d9b9 100644 --- a/doomsday/Src/p_particle.c +++ b/doomsday/Src/p_particle.c @@ -603,6 +603,19 @@ float P_GetParticleRadius(ded_ptcstage_t *stage_def, int ptc_index) + (1 - stage_def->radius_variance)) * stage_def->radius; } +//=========================================================================== +// P_GetParticleZ +// A particle may be attached to the floor or ceiling of the sector. +//=========================================================================== +fixed_t P_GetParticleZ(particle_t *pt) +{ + if(pt->pos[VZ] == DDMAXINT) + return pt->sector->ceilingheight - 2*FRACUNIT; + if(pt->pos[VZ] == DDMININT) + return pt->sector->floorheight + 2*FRACUNIT; + return pt->pos[VZ]; +} + //=========================================================================== // P_MoveParticle // The movement is done in two steps: @@ -615,6 +628,7 @@ void P_MoveParticle(ptcgen_t *gen, particle_t *pt) int x, y, z, xl, xh, yl, yh, bx, by; ptcstage_t *st = gen->stages + pt->stage; boolean zbounce = false; + boolean hitFloor; fixed_t hardRadius = st->radius/2; // Changes to momentum. @@ -632,7 +646,8 @@ void P_MoveParticle(ptcgen_t *gen, particle_t *pt) { delta[VX] = pt->pos[VX] - gen->source->x; delta[VY] = pt->pos[VY] - gen->source->y; - delta[VZ] = pt->pos[VZ] - (gen->source->z + gen->center[VZ]); + delta[VZ] = P_GetParticleZ(pt) + - (gen->source->z + gen->center[VZ]); } else { @@ -684,37 +699,55 @@ void P_MoveParticle(ptcgen_t *gen, particle_t *pt) // collisions. if(st->flags & PTCF_PLANE_FLAT) hardRadius = FRACUNIT; - // Check the new Z position. - z = pt->pos[VZ] + pt->mov[VZ]; - if(z > pt->sector->ceilingheight - hardRadius) + // Check the new Z position only if not stuck to a plane. + if(pt->pos[VZ] != DDMININT && pt->pos[VZ] != DDMAXINT) { - // The Z is through the roof! - if(pt->sector->ceilingpic == skyflatnum) + z = pt->pos[VZ] + pt->mov[VZ]; + if(z > pt->sector->ceilingheight - hardRadius) { - // Special case: particle gets lost in the sky. - pt->stage = -1; - return; + // The Z is through the roof! + if(pt->sector->ceilingpic == skyflatnum) + { + // Special case: particle gets lost in the sky. + pt->stage = -1; + return; + } + if(!P_TouchParticle(pt, st, false)) return; + z = pt->sector->ceilingheight - hardRadius; + zbounce = true; + hitFloor = false; } - if(!P_TouchParticle(pt, st, false)) return; - z = pt->sector->ceilingheight - hardRadius; - zbounce = true; - } - // Also check the floor. - if(z < pt->sector->floorheight + hardRadius) - { - if(pt->sector->floorpic == skyflatnum) + // Also check the floor. + if(z < pt->sector->floorheight + hardRadius) { - pt->stage = -1; - return; + if(pt->sector->floorpic == skyflatnum) + { + pt->stage = -1; + return; + } + if(!P_TouchParticle(pt, st, false)) return; + z = pt->sector->floorheight + hardRadius; + zbounce = true; + hitFloor = true; + } + if(zbounce) + { + pt->mov[VZ] = FixedMul(-pt->mov[VZ], st->bounce); + if(!pt->mov[VZ]) + { + // The particle has stopped moving. This means its Z-movement + // has ceased because of the collision with a plane. Plane-flat + // particles will stick to the plane. + if(st->flags & PTCF_PLANE_FLAT) + { + z = hitFloor? DDMININT : DDMAXINT; + } + } } - if(!P_TouchParticle(pt, st, false)) return; - z = pt->sector->floorheight + hardRadius; - zbounce = true; + + // Move to the new Z coordinate. + pt->pos[VZ] = z; } - if(zbounce) pt->mov[VZ] = FixedMul(-pt->mov[VZ], st->bounce); - - // Move to the new Z coordinate. - pt->pos[VZ] = z; // Now check the XY direction. // - Check if the movement crosses any solid lines. @@ -739,8 +772,9 @@ void P_MoveParticle(ptcgen_t *gen, particle_t *pt) { // If the particle is in the opening of a 2-sided line, it's // quite likely that it shouldn't be here... - if(pt->pos[VZ] > MAX_OF(front->floorheight, back->floorheight) - && pt->pos[VZ] < MIN_OF(front->ceilingheight, + if(P_GetParticleZ(pt) > MAX_OF(front->floorheight, + back->floorheight) + && P_GetParticleZ(pt) < MIN_OF(front->ceilingheight, back->ceilingheight)) { // Kill the particle. diff --git a/doomsday/Src/rend_particle.c b/doomsday/Src/rend_particle.c index 2e0f64ddcf..313bf038f0 100644 --- a/doomsday/Src/rend_particle.c +++ b/doomsday/Src/rend_particle.c @@ -5,6 +5,11 @@ //** //** Rendering of particle generators. //** +//** $Log$ +//** Revision 1.2 2003/02/28 10:42:15 skyjake +//** Added textured particles, planeflat sticks to planes +//** +//** //************************************************************************** // HEADER FILES ------------------------------------------------------------ @@ -21,6 +26,9 @@ // MACROS ------------------------------------------------------------------ +// Point + custom textures. +#define NUM_TEX_NAMES (1 + MAX_PTC_TEXTURES) + // TYPES ------------------------------------------------------------------- typedef struct pglink_s @@ -50,7 +58,7 @@ extern float vang, vpitch; // PUBLIC DATA DEFINITIONS ------------------------------------------------- -DGLuint ptctexname; // Name of the particle texture. +DGLuint ptctexname[NUM_TEX_NAMES]; int rend_particle_nearlimit = 0; float rend_particle_diffuse = 4; @@ -61,7 +69,7 @@ static pglink_t *pgstore; static int pgcursor, pgmax; static porder_t *order; static int numparts; -static boolean haspoints, haslines, hasnoblend, hasblend; +static boolean haspoints[NUM_TEX_NAMES], haslines, hasnoblend, hasblend; // CODE -------------------------------------------------------------------- @@ -89,6 +97,10 @@ void PG_InitTextures(void) // We need to generate the texture, I see. byte *image = Z_Malloc(64 * 64, PU_STATIC, 0); byte *data = W_CacheLumpName("DLIGHT", PU_CACHE); + int i; + + // Clear the texture names array. + memset(ptctexname, 0, sizeof(ptctexname)); if(!data) Con_Error("PG_InitTextures: No DLIGHT texture.\n"); @@ -99,7 +111,8 @@ void PG_InitTextures(void) memset(image, 255, 32 * 32); // No further mipmapping or resizing is needed, upload directly. - ptctexname = gl.NewTexture(); + // The zeroth texture is the default: a blurred point. + ptctexname[0] = gl.NewTexture(); gl.TexImage(DGL_LUMINANCE_PLUS_A8, 32, 32, 0, image); gl.TexParameter(DGL_MIN_FILTER, DGL_LINEAR); gl.TexParameter(DGL_MAG_FILTER, DGL_LINEAR); @@ -107,6 +120,43 @@ void PG_InitTextures(void) gl.TexParameter(DGL_WRAP_T, DGL_CLAMP); Z_Free(image); + + // Load any custom particle textures. They are loaded from the + // highres texture directory and are named "ParticleNN.(tga|png|pcx)". + // The first is "Particle00". (based on Leesz' textured particles mod) + for(i = 0; i < MAX_PTC_TEXTURES; i++) + { + char filename[80]; + int width, height, pixsize; + boolean masked; + + // Try to load the texture. + sprintf(filename, "Particle%02i", i); + if(!(image = GL_LoadHighResTexture(filename, &width, &height, + &pixsize, &masked))) + { + if(verbose) Con_Message("PG_InitTextures: %s not found.\n", + filename); + continue; + } + + // Create a new texture and upload the image. + ptctexname[i + 1] = gl.NewTexture(); + if(verbose) + { + Con_Message("PG_InitTextures: Texture %02i: %i * %i * %i\n", + i, width, height, pixsize); + } + gl.TexImage(pixsize == 4? DGL_RGBA : DGL_RGB, + width, height, 0, image); + gl.TexParameter(DGL_MIN_FILTER, DGL_LINEAR); + gl.TexParameter(DGL_MAG_FILTER, DGL_LINEAR); + gl.TexParameter(DGL_WRAP_S, DGL_CLAMP); + gl.TexParameter(DGL_WRAP_T, DGL_CLAMP); + + // Free the buffer. + M_Free(image); + } } //=========================================================================== @@ -114,8 +164,8 @@ void PG_InitTextures(void) //=========================================================================== void PG_ShutdownTextures(void) { - gl.DeleteTextures(1, &ptctexname); - ptctexname = 0; + gl.DeleteTextures(NUM_TEX_NAMES, ptctexname); + memset(ptctexname, 0, sizeof(ptctexname)); } //=========================================================================== @@ -225,13 +275,14 @@ int __cdecl PG_Sorter(const void *pt1, const void *pt2) //=========================================================================== int PG_ListVisibleParticles(void) { - int i, p, m; + int i, p, m, stagetype; fixed_t maxdist, mindist = FRACUNIT * rend_particle_nearlimit; ptcgen_t *gen; ded_ptcgen_t *def; particle_t *pt; - haspoints = haslines = hasblend = hasnoblend = false; + haslines = hasblend = hasnoblend = false; + memset(haspoints, 0, sizeof(haspoints)); // First count how many particles are in the visible generators. for(i = 0, numparts = 0; i < MAX_ACTIVE_PTCGENS; i++) @@ -246,6 +297,8 @@ int PG_ListVisibleParticles(void) // Allocate the rendering order list. order = Z_Malloc(sizeof(*order) * numparts, PU_STATIC, 0); + // Fill in the order list and see what kind of particles we'll + // need to render. for(i = 0, m = 0; i < MAX_ACTIVE_PTCGENS; i++) { gen = active_ptcgens[i]; @@ -265,10 +318,22 @@ int PG_ListVisibleParticles(void) if(!order[m].distance) order[m].distance = 1; if(maxdist && order[m].distance > maxdist) continue; // Too far. if(order[m].distance < mindist) continue; // Too near. - if(gen->stages[pt->stage].type == PTC_POINT) - haspoints = true; - if(gen->stages[pt->stage].type == PTC_LINE) + + stagetype = gen->stages[pt->stage].type; + if(stagetype == PTC_POINT) + { + haspoints[0] = true; + } + else if(stagetype == PTC_LINE) + { haslines = true; + } + else if(stagetype >= PTC_TEXTURE + && stagetype < PTC_TEXTURE + MAX_PTC_TEXTURES) + { + haspoints[stagetype - PTC_TEXTURE + 1] = true; + } + if(gen->flags & PGF_ADD_BLEND) hasblend = true; else @@ -305,6 +370,7 @@ void PG_RenderParticles(int rtype, boolean with_blend) particle_t *pt; ded_ptcstage_t *dst, *next_dst; int i, c; + int using_texture = -1; // viewsidevec points to the left. for(i = 0; i < 3; i++) @@ -313,11 +379,17 @@ void PG_RenderParticles(int rtype, boolean with_blend) rightoff[i] = viewupvec[i] - viewsidevec[i]; } + // Should we use a texture? if(rtype == PTC_POINT) + using_texture = 0; + else if(rtype >= PTC_TEXTURE && rtype < PTC_TEXTURE + MAX_PTC_TEXTURES) + using_texture = rtype - PTC_TEXTURE + 1; + + if(using_texture >= 0) { gl.Disable(DGL_DEPTH_WRITE); gl.Disable(DGL_CULL_FACE); - gl.Bind(ptctexname); + gl.Bind(ptctexname[using_texture]); gl.Begin(DGL_QUADS); // A waste of vertices and triangles, but... gl.Func(DGL_DEPTH_TEST, DGL_LEQUAL, 0); } @@ -397,10 +469,10 @@ void PG_RenderParticles(int rtype, boolean with_blend) center[VX] = FIX2FLT(pt->pos[VX]); center[VZ] = FIX2FLT(pt->pos[VY]); - center[VY] = FIX2FLT(pt->pos[VZ]); + center[VY] = FIX2FLT(P_GetParticleZ(pt)); // The vertices, please. - if(rtype == PTC_POINT) + if(using_texture >= 0) { // Should the particle be flat against a plane? if(st->flags & PTCF_PLANE_FLAT @@ -482,7 +554,7 @@ void PG_RenderParticles(int rtype, boolean with_blend) center[VZ] - size*rightoff[VZ]); } } - else // Line? + else // It's a line. { gl.Vertex3f(center[VX], center[VY], center[VZ]); gl.Vertex3f(center[VX] - FIX2FLT(pt->mov[VX]), @@ -493,7 +565,7 @@ void PG_RenderParticles(int rtype, boolean with_blend) gl.End(); - if(rtype == PTC_POINT) + if(using_texture >= 0) { gl.Enable(DGL_DEPTH_WRITE); gl.Enable(DGL_CULL_FACE); @@ -505,6 +577,33 @@ void PG_RenderParticles(int rtype, boolean with_blend) } } +//=========================================================================== +// PG_RenderPass +// +//=========================================================================== +void PG_RenderPass(boolean use_blending) +{ + int i; + + // Set blending mode. + if(use_blending) + gl.Func(DGL_BLENDING, DGL_SRC_ALPHA, DGL_ONE); + + if(haslines) + PG_RenderParticles(PTC_LINE, use_blending); + + for(i = 0; i < NUM_TEX_NAMES; i++) + if(haspoints[i]) + { + PG_RenderParticles(!i? PTC_POINT : PTC_TEXTURE + i - 1, + use_blending); + } + + // Restore blending mode. + if(use_blending) + gl.Func(DGL_BLENDING, DGL_SRC_ALPHA, DGL_ONE_MINUS_SRC_ALPHA); +} + //=========================================================================== // PG_Render // Render all the visible particle generators. @@ -520,18 +619,21 @@ void PG_Render(void) // Render all the visible particles. if(hasnoblend) { - if(haslines) PG_RenderParticles(PTC_LINE, false); - if(haspoints) PG_RenderParticles(PTC_POINT, false); + PG_RenderPass(false); +/* if(haslines) PG_RenderParticles(PTC_LINE, false); + if(haspoints) PG_RenderParticles(PTC_POINT, false);*/ } if(hasblend) { // A second pass with additive blending. - gl.Func(DGL_BLENDING, DGL_SRC_ALPHA, DGL_ONE); +/* gl.Func(DGL_BLENDING, DGL_SRC_ALPHA, DGL_ONE); if(haslines) PG_RenderParticles(PTC_LINE, true); if(haspoints) PG_RenderParticles(PTC_POINT, true); - gl.Func(DGL_BLENDING, DGL_SRC_ALPHA, DGL_ONE_MINUS_SRC_ALPHA); + gl.Func(DGL_BLENDING, DGL_SRC_ALPHA, DGL_ONE_MINUS_SRC_ALPHA);*/ + PG_RenderPass(true); } // Free the list allocated in PG_ListVisibleParticles. + // FIXME: Is this necessary? Z_Free(order); } \ No newline at end of file