X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=cl_particles.c;h=25e8b8b15740e05b45195ee7969dc976bbdb328f;hb=d35a3da5c044ae514578d133eced5a9e8ee17bb0;hp=679778a5d455f2fd8bbb3e11ac49d375a36e5752;hpb=e4e9ebace60585c6cfb51cafda868761e8d21458;p=xonotic%2Fdarkplaces.git diff --git a/cl_particles.c b/cl_particles.c index 679778a5..25e8b8b1 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -192,6 +192,81 @@ static const int tex_bubble = 62; static const int tex_raindrop = 61; static const int tex_beam = 60; +particleeffectinfo_t baselineparticleeffectinfo = +{ + 0, //int effectnameindex; // which effect this belongs to + // PARTICLEEFFECT_* bits + 0, //int flags; + // blood effects may spawn very few particles, so proper fraction-overflow + // handling is very important, this variable keeps track of the fraction + 0.0, //double particleaccumulator; + // the math is: countabsolute + requestedcount * countmultiplier * quality + // absolute number of particles to spawn, often used for decals + // (unaffected by quality and requestedcount) + 0.0f, //float countabsolute; + // multiplier for the number of particles CL_ParticleEffect was told to + // spawn, most effects do not really have a count and hence use 1, so + // this is often the actual count to spawn, not merely a multiplier + 0.0f, //float countmultiplier; + // if > 0 this causes the particle to spawn in an evenly spaced line from + // originmins to originmaxs (causing them to describe a trail, not a box) + 0.0f, //float trailspacing; + // type of particle to spawn (defines some aspects of behavior) + pt_alphastatic, //ptype_t particletype; + // blending mode used on this particle type + PBLEND_ALPHA, //pblend_t blendmode; + // orientation of this particle type (BILLBOARD, SPARK, BEAM, etc) + PARTICLE_BILLBOARD, //porientation_t orientation; + // range of colors to choose from in hex RRGGBB (like HTML color tags), + // randomly interpolated at spawn + {0xFFFFFF, 0xFFFFFF}, //unsigned int color[2]; + // a random texture is chosen in this range (note the second value is one + // past the last choosable, so for example 8,16 chooses any from 8 up and + // including 15) + // if start and end of the range are the same, no randomization is done + {63, 63 /* tex_particle */}, //int tex[2]; + // range of size values randomly chosen when spawning, plus size increase over time + {1, 1, 0.0f}, //float size[3]; + // range of alpha values randomly chosen when spawning, plus alpha fade + {0.0f, 256.0f, 256.0f}, //float alpha[3]; + // how long the particle should live (note it is also removed if alpha drops to 0) + {16777216.0f, 16777216.0f}, //float time[2]; + // how much gravity affects this particle (negative makes it fly up!) + 0.0f, //float gravity; + // how much bounce the particle has when it hits a surface + // if negative the particle is removed on impact + 0.0f, //float bounce; + // if in air this friction is applied + // if negative the particle accelerates + 0.0f, //float airfriction; + // if in liquid (water/slime/lava) this friction is applied + // if negative the particle accelerates + 0.0f, //float liquidfriction; + // these offsets are added to the values given to particleeffect(), and + // then an ellipsoid-shaped jitter is added as defined by these + // (they are the 3 radii) + 1.0f, //float stretchfactor; + // stretch velocity factor (used for sparks) + {0.0f, 0.0f, 0.0f}, //float originoffset[3]; + {0.0f, 0.0f, 0.0f}, //float velocityoffset[3]; + {0.0f, 0.0f, 0.0f}, //float originjitter[3]; + {0.0f, 0.0f, 0.0f}, //float velocityjitter[3]; + 0.0f, //float velocitymultiplier; + // an effect can also spawn a dlight + 0.0f, //float lightradiusstart; + 0.0f, //float lightradiusfade; + 16777216.0f, //float lighttime; + {1.0f, 1.0f, 1.0f}, //float lightcolor[3]; + true, //qboolean lightshadow; + 0, //int lightcubemapnum; + {(unsigned int)-1, (unsigned int)-1}, //unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color! + {-1, -1}, //int staintex[2]; + {1.0f, 1.0f}, //float stainalpha[2]; + {2.0f, 2.0f}, //float stainsize[2]; + // other parameters + {0.0f, 360.0f, 0.0f, 0.0f}, //float rotate[4]; // min/max base angle, min/max rotation over time +}; + cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1", "enables particle effects"}; cvar_t cl_particles_quality = {CVAR_SAVE, "cl_particles_quality", "1", "multiplies number of particles"}; cvar_t cl_particles_alpha = {CVAR_SAVE, "cl_particles_alpha", "1", "multiplies opacity of particles"}; @@ -289,37 +364,9 @@ void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, co break; } info = particleeffectinfo + numparticleeffectinfo++; + // copy entire info from baseline, then fix up the nameindex + *info = baselineparticleeffectinfo; info->effectnameindex = effectnameindex; - info->particletype = pt_alphastatic; - info->blendmode = particletype[info->particletype].blendmode; - info->orientation = particletype[info->particletype].orientation; - info->tex[0] = tex_particle; - info->tex[1] = tex_particle; - info->color[0] = 0xFFFFFF; - info->color[1] = 0xFFFFFF; - info->size[0] = 1; - info->size[1] = 1; - info->alpha[0] = 0; - info->alpha[1] = 256; - info->alpha[2] = 256; - info->time[0] = 9999; - info->time[1] = 9999; - VectorSet(info->lightcolor, 1, 1, 1); - info->lightshadow = true; - info->lighttime = 9999; - info->stretchfactor = 1; - info->staincolor[0] = (unsigned int)-1; - info->staincolor[1] = (unsigned int)-1; - info->staintex[0] = -1; - info->staintex[1] = -1; - info->stainalpha[0] = 1; - info->stainalpha[1] = 1; - info->stainsize[0] = 2; - info->stainsize[1] = 2; - info->rotate[0] = 0; - info->rotate[1] = 360; - info->rotate[2] = 0; - info->rotate[3] = 0; } else if (info == NULL) { @@ -602,6 +649,12 @@ particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, i part->color[0] = ((((pcolor1 >> 16) & 0xFF) * l1 + ((pcolor2 >> 16) & 0xFF) * l2) >> 8) & 0xFF; part->color[1] = ((((pcolor1 >> 8) & 0xFF) * l1 + ((pcolor2 >> 8) & 0xFF) * l2) >> 8) & 0xFF; part->color[2] = ((((pcolor1 >> 0) & 0xFF) * l1 + ((pcolor2 >> 0) & 0xFF) * l2) >> 8) & 0xFF; + if (vid.sRGB3D) + { + part->color[0] = (unsigned char)(Image_LinearFloatFromsRGB(part->color[0]) * 256.0f); + part->color[1] = (unsigned char)(Image_LinearFloatFromsRGB(part->color[1]) * 256.0f); + part->color[2] = (unsigned char)(Image_LinearFloatFromsRGB(part->color[2]) * 256.0f); + } part->alpha = palpha; part->alphafade = palphafade; part->staintexnum = staintex; @@ -682,7 +735,7 @@ particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, i part->typeindex = pt_spark; part->bounce = 0; VectorMA(part->org, lifetime, part->vel, endvec); - trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, true, false, NULL, false); + trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, true, false, NULL, false, false); part->die = cl.time + lifetime * trace.fraction; part2 = CL_NewParticle(endvec, pt_raindecal, pcolor1, pcolor2, tex_rainsplash, part->size, part->size * 20, part->alpha, part->alpha / 0.4, 0, 0, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2], 0, 0, 0, 0, pqualityreduction, 0, 1, PBLEND_ADD, PARTICLE_ORIENTED_DOUBLESIDED, -1, -1, -1, 1, 1, 0, 0, NULL); if (part2) @@ -758,7 +811,10 @@ void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t if (cl_decals_newsystem.integer) { - R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size); + if (vid.sRGB3D) + R_DecalSystem_SplatEntities(org, normal, Image_LinearFloatFromsRGB(color[0]), Image_LinearFloatFromsRGB(color[1]), Image_LinearFloatFromsRGB(color[2]), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size); + else + R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size); return; } @@ -780,6 +836,12 @@ void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t decal->color[0] = color[0]; decal->color[1] = color[1]; decal->color[2] = color[2]; + if (vid.sRGB3D) + { + decal->color[0] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[0]) * 256.0f); + decal->color[1] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[1]) * 256.0f); + decal->color[2] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[2]) * 256.0f); + } decal->owner = hitent; decal->clusterindex = -1000; // no vis culling unless we're sure if (hitent) @@ -812,7 +874,7 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, { VectorRandom(org2); VectorMA(org, maxdist, org2, org2); - trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, true, false, &hitent, false); + trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, true, false, &hitent, false, true); // take the closest trace result that doesn't end up hitting a NOMARKS // surface (sky for example) if (bestfrac > trace.fraction && !(trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS)) @@ -1693,7 +1755,7 @@ void CL_ParticleExplosion (const vec3_t org) { VectorRandom(v2); VectorMA(org, 128, v2, v); - trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false); + trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false); } while (k < 16 && trace.fraction < 0.1f); VectorSubtract(trace.endpos, org, v2); @@ -1824,11 +1886,11 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in } } -static cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"}; +cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"}; static cvar_t r_drawparticles_drawdistance = {CVAR_SAVE, "r_drawparticles_drawdistance", "2000", "particles further than drawdistance*size will not be drawn"}; static cvar_t r_drawparticles_nearclip_min = {CVAR_SAVE, "r_drawparticles_nearclip_min", "4", "particles closer than drawnearclip_min will not be drawn"}; static cvar_t r_drawparticles_nearclip_max = {CVAR_SAVE, "r_drawparticles_nearclip_max", "4", "particles closer than drawnearclip_min will be faded"}; -static cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"}; +cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"}; static cvar_t r_drawdecals_drawdistance = {CVAR_SAVE, "r_drawdecals_drawdistance", "500", "decals further than drawdistance*size will not be drawn"}; #define PARTICLETEXTURESIZE 64 @@ -1983,6 +2045,7 @@ static void R_InitParticleTexture (void) char *buf; fs_offset_t filesize; char texturename[MAX_QPATH]; + skinframe_t *sf; // a note: decals need to modulate (multiply) the background color to // properly darken it (stain), and they need to be able to alpha fade, @@ -2139,7 +2202,7 @@ static void R_InitParticleTexture (void) Image_WriteTGABGRA ("particles/particlefont.tga", PARTICLEFONTSIZE, PARTICLEFONTSIZE, particletexturedata); #endif - decalskinframe = R_SkinFrame_LoadInternalBGRA("particlefont", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, particletexturedata, PARTICLEFONTSIZE, PARTICLEFONTSIZE); + decalskinframe = R_SkinFrame_LoadInternalBGRA("particlefont", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, particletexturedata, PARTICLEFONTSIZE, PARTICLEFONTSIZE, false); particlefonttexture = decalskinframe->base; Mem_Free(particletexturedata); @@ -2158,7 +2221,7 @@ static void R_InitParticleTexture (void) } #ifndef DUMPPARTICLEFONT - particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, r_texture_convertsRGB_particles.integer != 0); + particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, vid.sRGB3D); if (!particletexture[tex_beam].texture) #endif { @@ -2241,7 +2304,13 @@ static void R_InitParticleTexture (void) Con_Printf("particles/particlefont.txt: texnum %i outside valid range (0 to %i)\n", i, MAX_PARTICLETEXTURES); continue; } - particletexture[i].texture = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, false)->base; + sf = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true); + if(!sf) + { + // R_SkinFrame_LoadExternal already complained + continue; + } + particletexture[i].texture = sf->base; particletexture[i].s1 = s1; particletexture[i].t1 = t1; particletexture[i].s2 = s2; @@ -2274,14 +2343,13 @@ static void r_part_newmap(void) CL_Particles_LoadEffectInfo(); } -#define BATCHSIZE 256 -unsigned short particle_elements[BATCHSIZE*6]; -float particle_vertex3f[BATCHSIZE*12], particle_texcoord2f[BATCHSIZE*8], particle_color4f[BATCHSIZE*16]; +unsigned short particle_elements[MESHQUEUE_TRANSPARENT_BATCHSIZE*6]; +float particle_vertex3f[MESHQUEUE_TRANSPARENT_BATCHSIZE*12], particle_texcoord2f[MESHQUEUE_TRANSPARENT_BATCHSIZE*8], particle_color4f[MESHQUEUE_TRANSPARENT_BATCHSIZE*16]; void R_Particles_Init (void) { int i; - for (i = 0;i < BATCHSIZE;i++) + for (i = 0;i < MESHQUEUE_TRANSPARENT_BATCHSIZE;i++) { particle_elements[i*6+0] = i*4+0; particle_elements[i*6+1] = i*4+1; @@ -2368,7 +2436,7 @@ void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t // now render the decals all at once // (this assumes they all use one particle font texture!) GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1); + R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1, false, false); R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f); R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, NULL, 0, particle_elements, NULL, 0); } @@ -2461,7 +2529,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh float *v3f, *t2f, *c4f; particletexture_t *tex; float up2[3], v[3], right[3], up[3], fog, ifog, size, len, lenfactor, alpha; - float ambient[3], diffuse[3], diffusenormal[3]; +// float ambient[3], diffuse[3], diffusenormal[3]; float palpha, spintime, spinrad, spincos, spinsin, spinm1, spinm2, spinm3, spinm4, baseright[3], baseup[3]; vec4_t colormultiplier; float minparticledist_start, minparticledist_end; @@ -2477,7 +2545,6 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh GL_DepthRange(0, 1); GL_PolygonOffset(0, 0); GL_DepthTest(true); - GL_AlphaTest(false); GL_CullFace(GL_NONE); spintime = r_refdef.scene.time; @@ -2531,12 +2598,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh c4f[3] = alpha; // note: lighting is not cheap! if (particletype[p->typeindex].lighting) - { - R_CompleteLightPoint(ambient, diffuse, diffusenormal, p->org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); - c4f[0] *= (ambient[0] + 0.5 * diffuse[0]); - c4f[1] *= (ambient[1] + 0.5 * diffuse[1]); - c4f[2] *= (ambient[2] + 0.5 * diffuse[2]); - } + R_LightPoint(c4f, p->org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); // mix in the fog color if (r_refdef.fogenabled) { @@ -2684,7 +2746,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh if (texture != particletexture[p->texnum].texture) { texture = particletexture[p->texnum].texture; - R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1); + R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1, false, false); } if (p->blendmode == PBLEND_INVMOD) @@ -2791,7 +2853,7 @@ void R_DrawParticles (void) // if (p->bounce && cl.time >= p->delayedcollisions) if (p->bounce && cl_particles_collisions.integer && VectorLength(p->vel)) { - trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, false); + trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, false, false); // if the trace started in or hit something of SUPERCONTENTS_NODROP // or if the trace hit something flagged as NOIMPACT // then remove the particle