#include "quakedef.h"
-#define MAX_PARTICLES 4096 // default max # of particles at one time
+#define MAX_PARTICLES 16384 // default max # of particles at one time
#define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's on the command line
// LordHavoc: added dust, smoke, snow, bloodcloud, and many others
typedef enum
{
- pt_static, pt_grav, pt_blob, pt_blob2, pt_smoke, pt_snow, pt_rain, pt_bloodcloud, pt_fallfadespark, pt_bubble, pt_fade, pt_smokecloud, pt_splash, pt_flame, pt_flamingdebris, pt_smokingdebris, pt_flamefall
+ pt_static, pt_grav, pt_slowgrav, pt_blob, pt_blob2, pt_bulletsmoke, pt_smoke, pt_snow, pt_rain, pt_spark, pt_bubble, pt_fade, pt_steam, pt_splash, pt_splashpuff, pt_flame/*, pt_decal*/, pt_blood, pt_oneframe, pt_lavasplash
}
ptype_t;
float die;
ptype_t type;
float scale;
- short texnum;
- short dynlight; // if set the particle will be dynamically lit (if r_dynamicparticles is on), used for smoke and blood
+ rtexture_t *tex;
+ byte dynlight; // if set the particle will be dynamically lit (if r_dynamicparticles is on), used for smoke and blood
+ byte rendermode; // a TPOLYTYPE_ value
+ byte pad1;
+ byte pad2;
float alpha; // 0-255
float time2; // used for various things (snow fluttering, for example)
+ float bounce; // how much bounce-back from a surface the particle hits (0 = no physics, 1 = stop and slide, 2 = keep bouncing forever, 1.5 is typical of bouncing particles)
vec3_t oldorg;
vec3_t vel2; // used for snow fluttering (base velocity, wind for instance)
+// vec3_t direction; // used by decals
+// vec3_t decalright; // used by decals
+// vec3_t decalup; // used by decals
}
particle_t;
int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
int ramp3[8] = {0x6d, 0x6b, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
-int particletexture;
-int smokeparticletexture[8];
-int rainparticletexture;
-int bubbleparticletexture;
-int explosiontexture;
-int explosiontexturefog;
+rtexture_t *particletexture;
+rtexture_t *smokeparticletexture[8];
+rtexture_t *rainparticletexture;
+rtexture_t *bubbleparticletexture;
+rtexture_t *bulletholetexture[8];
particle_t *particles;
int r_numparticles;
int numparticles;
particle_t **freeparticles; // list used only in compacting particles array
-// LordHavoc: reduced duplicate code, and allow particle allocation system independence
-#define ALLOCPARTICLE(part) \
- if (numparticles >= r_numparticles)\
- return;\
- (part) = &particles[numparticles++];
-
-cvar_t r_particles = {"r_particles", "1"};
+cvar_t r_particles = {"r_particles", "1", true};
cvar_t r_drawparticles = {"r_drawparticles", "1"};
-cvar_t r_dynamicparticles = {"r_dynamicparticles", "0", TRUE};
+cvar_t r_particles_lighting = {"r_particles_lighting", "1", true};
+cvar_t r_particles_bloodshowers = {"r_particles_bloodshowers", "1", true};
+cvar_t r_particles_blood = {"r_particles_blood", "1", true};
+cvar_t r_particles_smoke = {"r_particles_smoke", "1", true};
+cvar_t r_particles_sparks = {"r_particles_sparks", "1", true};
+cvar_t r_particles_bubbles = {"r_particles_bubbles", "1", true};
byte shadebubble(float dx, float dy, vec3_t light)
{
float dz, f, dot;
vec3_t normal;
- if ((dx*dx+dy*dy) < 1) // it does hit the sphere
+ dz = 1 - (dx*dx+dy*dy);
+ if (dz > 0) // it does hit the sphere
{
- dz = 1 - (dx*dx+dy*dy);
f = 0;
// back side
normal[0] = dx;normal[1] = dy;normal[2] = dz;
{
int x,y,d,i,m;
float dx, dy;
- byte data[32][32][4], noise1[128][128], noise2[128][128];
+ byte data[32][32][4], noise1[64][64], noise2[64][64];
vec3_t light;
for (y = 0;y < 32;y++)
{
data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
dx = x - 16;
- d = (255 - (dx*dx+dy*dy));
- if (d < 0) d = 0;
+ d = (256 - (dx*dx+dy*dy));
+ d = bound(0, d, 255);
data[y][x][3] = (byte) d;
}
}
- particletexture = GL_LoadTexture ("particletexture", 32, 32, &data[0][0][0], true, true, 4);
+ particletexture = R_LoadTexture ("particletexture", 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
for (i = 0;i < 8;i++)
{
do
{
- fractalnoise(&noise1[0][0], 128, 8);
- fractalnoise(&noise2[0][0], 128, 16);
+ fractalnoise(&noise1[0][0], 64, 4);
+ fractalnoise(&noise2[0][0], 64, 8);
m = 0;
for (y = 0;y < 32;y++)
{
dy = y - 16;
for (x = 0;x < 32;x++)
{
- int j;
- j = (noise1[y][x] - 128) * 2 + 128;
- if (j < 0) j = 0;
- if (j > 255) j = 255;
- data[y][x][0] = data[y][x][1] = data[y][x][2] = j;
+ d = (noise1[y][x] - 128) * 2 + 128;
+ d = bound(0, d, 255);
+ data[y][x][0] = data[y][x][1] = data[y][x][2] = d;
dx = x - 16;
d = (noise2[y][x] - 128) * 4 + 128;
if (d > 0)
- {
- d = (d * (255 - (int) (dx*dx+dy*dy))) >> 8;
- //j = (sqrt(dx*dx+dy*dy) * 2.0f - 16.0f);
- //if (j > 0)
- // d = (d * (255 - j*j)) >> 8;
- if (d < 0) d = 0;
- if (d > 255) d = 255;
- data[y][x][3] = (byte) d;
- if (m < d)
- m = d;
- }
+ d = (d * (256 - (int) (dx*dx+dy*dy))) >> 8;
+ d = bound(0, d, 255);
+ data[y][x][3] = (byte) d;
+ if (m < d)
+ m = d;
}
}
}
- while (m < 192);
+ while (m < 224);
- smokeparticletexture[i] = GL_LoadTexture (va("smokeparticletexture%d", i), 32, 32, &data[0][0][0], true, true, 4);
+ smokeparticletexture[i] = R_LoadTexture (va("smokeparticletexture%d", i), 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
}
light[0] = 1;light[1] = 1;light[2] = 1;
VectorNormalize(light);
- for (x=0 ; x<32 ; x++)
+ for (y = 0;y < 32;y++)
{
- for (y=0 ; y<32 ; y++)
+ for (x = 0;x < 32;x++)
{
data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
data[y][x][3] = shadebubble((x - 16) * (1.0 / 8.0), y < 24 ? (y - 24) * (1.0 / 24.0) : (y - 24) * (1.0 / 8.0), light);
}
}
- rainparticletexture = GL_LoadTexture ("rainparticletexture", 32, 32, &data[0][0][0], true, true, 4);
+ rainparticletexture = R_LoadTexture ("rainparticletexture", 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
light[0] = 1;light[1] = 1;light[2] = 1;
VectorNormalize(light);
- for (x=0 ; x<32 ; x++)
+ for (y = 0;y < 32;y++)
{
- for (y=0 ; y<32 ; y++)
+ for (x = 0;x < 32;x++)
{
data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
data[y][x][3] = shadebubble((x - 16) * (1.0 / 16.0), (y - 16) * (1.0 / 16.0), light);
}
}
- bubbleparticletexture = GL_LoadTexture ("bubbleparticletexture", 32, 32, &data[0][0][0], true, true, 4);
+ bubbleparticletexture = R_LoadTexture ("bubbleparticletexture", 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
+
+ for (i = 0;i < 8;i++)
+ {
+ float p[32][32];
+ fractalnoise(&noise1[0][0], 64, 8);
+ for (y = 0;y < 32;y++)
+ for (x = 0;x < 32;x++)
+ p[y][x] = (noise1[y][x] / 8.0f) - 64.0f;
+ for (m = 0;m < 32;m++)
+ {
+ int j;
+ float fx, fy, f;
+ fx = lhrandom(14, 18);
+ fy = lhrandom(14, 18);
+ do
+ {
+ dx = lhrandom(-1, 1);
+ dy = lhrandom(-1, 1);
+ f = (dx * dx + dy * dy);
+ }
+ while(f < 0.125f || f > 1.0f);
+ f = (m + 1) / 40.0f; //lhrandom(0.0f, 1.0);
+ dx *= 1.0f / 32.0f;
+ dy *= 1.0f / 32.0f;
+ for (j = 0;f > 0 && j < (32 * 14);j++)
+ {
+ y = fy;
+ x = fx;
+ fx += dx;
+ fy += dy;
+ p[y - 1][x - 1] += f * 0.125f;
+ p[y - 1][x ] += f * 0.25f;
+ p[y - 1][x + 1] += f * 0.125f;
+ p[y ][x - 1] += f * 0.25f;
+ p[y ][x ] += f;
+ p[y ][x + 1] += f * 0.25f;
+ p[y + 1][x - 1] += f * 0.125f;
+ p[y + 1][x ] += f * 0.25f;
+ p[y + 1][x + 1] += f * 0.125f;
+// f -= (0.5f / (32 * 16));
+ }
+ }
+ for (y = 0;y < 32;y++)
+ {
+ for (x = 0;x < 32;x++)
+ {
+ m = p[y][x];
+ data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
+ data[y][x][3] = (byte) bound(0, m, 255);
+ }
+ }
+
+ bulletholetexture[i] = R_LoadTexture (va("bulletholetexture%d", i), 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
+ }
}
void r_part_start()
qfree(freeparticles);
}
+void r_part_newmap()
+{
+ numparticles = 0;
+}
+
/*
===============
R_InitParticles
Cvar_RegisterVariable (&r_particles);
Cvar_RegisterVariable (&r_drawparticles);
- Cvar_RegisterVariable (&r_dynamicparticles);
-
- R_RegisterModule("R_Particles", r_part_start, r_part_shutdown);
+ Cvar_RegisterVariable (&r_particles_lighting);
+ Cvar_RegisterVariable (&r_particles_bloodshowers);
+ Cvar_RegisterVariable (&r_particles_blood);
+ Cvar_RegisterVariable (&r_particles_smoke);
+ Cvar_RegisterVariable (&r_particles_sparks);
+ Cvar_RegisterVariable (&r_particles_bubbles);
+
+ R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap);
}
-#define particle(ptype, pcolor, ptex, plight, pscale, palpha, ptime, px, py, pz, pvx, pvy, pvz)\
+//void particle(int ptype, int pcolor, int ptex, int prendermode, int plight, float pscale, float palpha, float ptime, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz)
+#define particle(ptype, pcolor, ptex, prendermode, plight, pscale, palpha, ptime, pbounce, px, py, pz, pvx, pvy, pvz)\
{\
particle_t *part;\
- ALLOCPARTICLE(part)\
+ if (numparticles >= r_numparticles)\
+ return;\
+ part = &particles[numparticles++];\
part->type = (ptype);\
part->color = (pcolor);\
- part->texnum = (ptex);\
+ part->tex = (ptex);\
part->dynlight = (plight);\
+ part->rendermode = (prendermode);\
part->scale = (pscale);\
part->alpha = (palpha);\
part->die = cl.time + (ptime);\
+ part->bounce = (pbounce);\
part->org[0] = (px);\
part->org[1] = (py);\
part->org[2] = (pz);\
part->vel[0] = (pvx);\
part->vel[1] = (pvy);\
part->vel[2] = (pvz);\
+ part->time2 = 0;\
+ part->vel2[0] = part->vel2[1] = part->vel2[2] = 0;\
}
-#define particle2(ptype, pcolor, ptex, plight, pscale, palpha, ptime, pbase, poscale, pvscale)\
+/*
+#define particle2(ptype, pcolor, ptex, prendermode, plight, pscale, palpha, ptime, pbounce, pbase, poscale, pvscale)\
{\
particle_t *part;\
- ALLOCPARTICLE(part)\
+ if (numparticles >= r_numparticles)\
+ return;\
+ part = &particles[numparticles++];\
part->type = (ptype);\
part->color = (pcolor);\
- part->texnum = (ptex);\
+ part->tex = (ptex);\
part->dynlight = (plight);\
+ part->rendermode = (prendermode);\
part->scale = (pscale);\
part->alpha = (palpha);\
part->die = cl.time + (ptime);\
+ part->bounce = (pbounce);\
part->org[0] = lhrandom(-(poscale), (poscale)) + (pbase)[0];\
part->org[1] = lhrandom(-(poscale), (poscale)) + (pbase)[1];\
part->org[2] = lhrandom(-(poscale), (poscale)) + (pbase)[2];\
part->vel[0] = lhrandom(-(pvscale), (pvscale));\
part->vel[1] = lhrandom(-(pvscale), (pvscale));\
part->vel[2] = lhrandom(-(pvscale), (pvscale));\
+ part->time2 = 0;\
+ part->vel2[0] = part->vel2[1] = part->vel2[2] = 0;\
}
-#define particle3(ptype, pcolor, ptex, plight, pscale, palpha, ptime, pbase, pscalex, pscaley, pscalez, pvscalex, pvscaley, pvscalez)\
+*/
+/*
+#define particle3(ptype, pcolor, ptex, prendermode, plight, pscale, palpha, ptime, pbounce, pbase, pscalex, pscaley, pscalez, pvscalex, pvscaley, pvscalez)\
{\
particle_t *part;\
- ALLOCPARTICLE(part)\
+ if (numparticles >= r_numparticles)\
+ return;\
+ part = &particles[numparticles++];\
part->type = (ptype);\
part->color = (pcolor);\
- part->texnum = (ptex);\
+ part->tex = (ptex);\
part->dynlight = (plight);\
+ part->rendermode = (prendermode);\
part->scale = (pscale);\
part->alpha = (palpha);\
part->die = cl.time + (ptime);\
+ part->bounce = (pbounce);\
part->org[0] = lhrandom(-(pscalex), (pscalex)) + (pbase)[0];\
part->org[1] = lhrandom(-(pscaley), (pscaley)) + (pbase)[1];\
part->org[2] = lhrandom(-(pscalez), (pscalez)) + (pbase)[2];\
part->vel[0] = lhrandom(-(pvscalex), (pvscalex));\
part->vel[1] = lhrandom(-(pvscaley), (pvscaley));\
part->vel[2] = lhrandom(-(pvscalez), (pvscalez));\
+ part->time2 = 0;\
+ part->vel2[0] = part->vel2[1] = part->vel2[2] = 0;\
+}
+*/
+#define particle4(ptype, pcolor, ptex, prendermode, plight, pscale, palpha, ptime, pbounce, px, py, pz, pvx, pvy, pvz, ptime2, pvx2, pvy2, pvz2)\
+{\
+ particle_t *part;\
+ if (numparticles >= r_numparticles)\
+ return;\
+ part = &particles[numparticles++];\
+ part->type = (ptype);\
+ part->color = (pcolor);\
+ part->tex = (ptex);\
+ part->dynlight = (plight);\
+ part->rendermode = (prendermode);\
+ part->scale = (pscale);\
+ part->alpha = (palpha);\
+ part->die = cl.time + (ptime);\
+ part->bounce = (pbounce);\
+ part->org[0] = (px);\
+ part->org[1] = (py);\
+ part->org[2] = (pz);\
+ part->vel[0] = (pvx);\
+ part->vel[1] = (pvy);\
+ part->vel[2] = (pvz);\
+ part->time2 = (ptime2);\
+ part->vel2[0] = (pvx2);\
+ part->vel2[1] = (pvy2);\
+ part->vel2[2] = (pvz2);\
}
/*
R_EntityParticles
===============
*/
-
-#define NUMVERTEXNORMALS 162
-extern float r_avertexnormals[NUMVERTEXNORMALS][3];
-vec3_t avelocities[NUMVERTEXNORMALS];
-float beamlength = 16;
-vec3_t avelocity = {23, 7, 3};
-float partstep = 0.01;
-float timescale = 0.01;
-
void R_EntityParticles (entity_t *ent)
{
- int count;
int i;
float angle;
float sp, sy, cp, cy;
vec3_t forward;
float dist;
+ float beamlength;
+ static vec3_t avelocities[NUMVERTEXNORMALS];
if (!r_particles.value) return; // LordHavoc: particles are optional
dist = 64;
- count = 50;
+ beamlength = 16;
if (!avelocities[0][0])
for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
forward[1] = cp*sy;
forward[2] = -sp;
- particle(pt_static, 0x6f, particletexture, false, 2, 255, 0, ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength, ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength, ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0);
+ particle(pt_oneframe, 0x6f, particletexture, TPOLYTYPE_ALPHA, false, 2, 255, 9999, 0, ent->origin[0] + m_bytenormals[i][0]*dist + forward[0]*beamlength, ent->origin[1] + m_bytenormals[i][1]*dist + forward[1]*beamlength, ent->origin[2] + m_bytenormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0);
}
}
-/*
-===============
-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;
-
- numparticles = 0;
-}
-
-
void R_ReadPointFile_f (void)
{
FILE *f;
Con_Printf ("Not enough free particles\n");
break;
}
- particle(pt_static, (-c)&15, particletexture, false, 2, 255, 99999, org[0], org[1], org[2], 0, 0, 0);
+ particle(pt_static, (-c)&15, particletexture, TPOLYTYPE_ALPHA, false, 2, 255, 99999, 0, org[0], org[1], org[2], 0, 0, 0);
}
fclose (f);
int i;
if (!r_particles.value) return; // LordHavoc: particles are optional
-// particle(pt_smoke, (rand()&7) + 8, smokeparticletexture[rand()&7], true, 30, 255, 2, org[0], org[1], org[2], 0, 0, 0);
+// particle(pt_smoke, (rand()&7) + 8, smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, true, 30, 255, 2, org[0], org[1], org[2], 0, 0, 0);
i = Mod_PointInLeaf(org, cl.worldmodel)->contents;
if (i == CONTENTS_SLIME || i == CONTENTS_WATER)
{
- for (i=0 ; i<128 ; i++)
- particle2(pt_bubble, (rand()&3) + 12, bubbleparticletexture, false, lhrandom(1, 2), 255, 2, org, 16, 96);
+ for (i = 0;i < 128;i++)
+ particle(pt_bubble, 254, bubbleparticletexture, TPOLYTYPE_ADD, false, lhrandom(1, 2), 255, 9999, 1.5, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-96, 96), lhrandom(-96, 96), lhrandom(-96, 96));
}
else
R_NewExplosion(org);
// int color;
float f, forg[3], fvel[3], fvel2[3];
// for (i = 0;i < 256;i++)
-// particle(pt_fallfadespark, ramp3[rand()%6], particletexture, false, 1.5, lhrandom(128, 255), 5, lhrandom(-16, 16) + org[0], lhrandom(-16, 16) + org[1], lhrandom(-16, 16) + org[2], lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192) + 192);
+// particle(pt_fallfadespark, ramp3[rand()%6], particletexture, TPOLYTYPE_ALPHA, false, 1.5, lhrandom(128, 255), 5, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(0, 384));
// for (i = 0;i < 256;i++)
-// particle2(pt_fallfadespark, ramp3[rand()%6], particletexture, false, 1.5, lhrandom(128, 255), 5, org, 15, 150);
+// particle(pt_fallfadespark, ramp3[rand()%6], particletexture, TPOLYTYPE_ALPHA, false, 1.5, lhrandom(128, 255), 5, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-150, 150), lhrandom(-150, 150), lhrandom(-150, 150));
for (i = 0;i < 32;i++)
{
fvel[0] = lhrandom(-150, 150);
fvel[1] = lhrandom(-150, 150);
fvel[2] = lhrandom(-150, 150) + 80;
-// particle(pt_flamefall, 106 + (rand()%6), particletexture, false, 3, 255, 5, forg[0] + lhrandom(-5, 5), forg[1] + lhrandom(-5, 5), forg[2] + lhrandom(-5, 5), fvel2[0], fvel2[1], fvel2[2]);
+// particle(pt_flamefall, 106 + (rand()%6), particletexture, TPOLYTYPE_ALPHA, false, 3, 255, 5, forg[0] + lhrandom(-5, 5), forg[1] + lhrandom(-5, 5), forg[2] + lhrandom(-5, 5), fvel2[0], fvel2[1], fvel2[2]);
for (j = 0;j < 64;j++)
{
forg[0] = lhrandom(-20, 20) + org[0];
fvel2[0] *= f;
fvel2[1] *= f;
fvel2[2] *= f;
- particle(pt_flamefall, 106 + (rand()%6), particletexture, false, 5, lhrandom(96, 192), 5, forg[0], forg[1], forg[2], fvel2[0], fvel2[1], fvel2[2]);
+ particle(pt_flamefall, 106 + (rand()%6), particletexture, TPOLYTYPE_ALPHA, false, 5, lhrandom(96, 192), 5, forg[0], forg[1], forg[2], fvel2[0], fvel2[1], fvel2[2]);
}
}
// for (i = 0;i < 16;i++)
-// particle2(pt_smoke, 12+(rand()&3), smokeparticletexture[rand()&7], true, 20, 192, 99, org, 20, 0);
+// particle(pt_smoke, 12+(rand()&3), smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, true, 20, 192, 99, org[0] + lhrandom(-20, 20), org[1] + lhrandom(-20, 20), org[2] + lhrandom(-20, 20), 0, 0, 0);
// for (i = 0;i < 50;i++)
-// particle2(pt_flamingdebris, ramp3[rand()%6], particletexture, false, 3, 255, 99, org, 10, 200);
+// particle(pt_flamingdebris, ramp3[rand()%6], particletexture, TPOLYTYPE_ALPHA, false, 3, 255, 99, org[0] + lhrandom(-10, 10), org[1] + lhrandom(-10, 10), org[2] + lhrandom(-10, 10), lhrandom(-200, 200), lhrandom(-200, 200), lhrandom(-200, 200));
// for (i = 0;i < 30;i++)
-// particle2(pt_smokingdebris, 10 + (rand()%6), particletexture, false, 2, 255, 99, org, 10, 100);
+// particle(pt_smokingdebris, 10 + (rand()%6), particletexture, TPOLYTYPE_ALPHA, false, 2, 255, 99, org[0] + lhrandom(-10, 10), org[1] + lhrandom(-10, 10), org[2] + lhrandom(-10, 10), lhrandom(-100, 100), lhrandom(-100, 100), lhrandom(-100, 100));
}
*/
}
if (!r_particles.value) return; // LordHavoc: particles are optional
for (i = 0;i < 512;i++)
- particle2(pt_fade, colorStart + (i % colorLength), particletexture, false, 1.5, 255, 0.3, org, 8, 192);
+ particle(pt_fade, colorStart + (i % colorLength), particletexture, TPOLYTYPE_ALPHA, false, 1.5, 255, 0.3, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192));
}
/*
int i;
if (!r_particles.value) return; // LordHavoc: particles are optional
- for (i=0 ; i<512 ; i++)
- particle3(pt_blob, 66+(rand()%6), particletexture, false, 2, 255, lhrandom(1, 1.4), org, 16, 16, 16, 4, 4, 128);
- for (i=0 ; i<512 ; i++)
- particle3(pt_blob2, 150+(rand()%6), particletexture, false, 2, 255, lhrandom(1, 1.4), org, 16, 16, 16, 4, 4, 128);
+ for (i = 0;i < 256;i++)
+ particle(pt_blob, 66+(rand()%6), particletexture, TPOLYTYPE_ALPHA, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128));
+ for (i = 0;i < 256;i++)
+ particle(pt_blob2, 150+(rand()%6), particletexture, TPOLYTYPE_ALPHA, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128));
}
/*
R_ParticleExplosion(org, false);
return;
}
- color &= ~7;
- if (count & 7)
- {
- particle2(pt_fade, color + (rand()&7), particletexture, false, 6, (count & 7) * 16 + (rand()&15), 1, org, 8, 15);
- count &= ~7;
- }
- count >>= 3;
while (count--)
- particle2(pt_fade, color + (rand()&7), particletexture, false, 6, 128, 1, org, 8, 15);
+ particle(pt_fade, color + (rand()&7), particletexture, TPOLYTYPE_ALPHA, false, 1, 128, 9999, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-15, 15), lhrandom(-15, 15), lhrandom(-15, 15));
}
// LordHavoc: added this for spawning sparks/dust (which have strong gravity)
{
if (!r_particles.value) return; // LordHavoc: particles are optional
+ R_Decal(org, bulletholetexture[rand()&7], 16, 0, 0, 0, 255);
+
// smoke puff
- particle(pt_smoke, 12+(rand()&3), smokeparticletexture[rand()&7], true, 8, 160, 99, org[0], org[1], org[2], 0, 0, 0);
- // sparks
- while(count--)
-// particle2(pt_fallfadespark, ramp3[rand()%6], particletexture, false, 1, lhrandom(0, 255), 5, org, 4, 96);
- particle(pt_fallfadespark, ramp3[rand()%6], particletexture, false, 1, lhrandom(0, 255), 5, lhrandom(-4, 4) + org[0], lhrandom(-4, 4) + org[1], lhrandom(-4, 4) + org[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64) + 64);
+ if (r_particles_smoke.value)
+ particle(pt_bulletsmoke, 10, smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, true, 5, 255, 9999, 0, org[0], org[1], org[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16));
+
+ if (r_particles_sparks.value)
+ {
+ // sparks
+ while(count--)
+ particle(pt_spark, ramp3[rand()%6], particletexture, TPOLYTYPE_ADD, false, 1, lhrandom(0, 255), 9999, 1.5, org[0], org[1], org[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(0, 128));
+ }
}
-void R_BloodPuff (vec3_t org)
+void R_BloodPuff (vec3_t org, vec3_t vel, int count)
{
+ // bloodcount is used to accumulate counts too small to cause a blood particle
+ static int bloodcount = 0;
if (!r_particles.value) return; // LordHavoc: particles are optional
+ if (!r_particles_blood.value) return;
- particle(pt_bloodcloud, 251 /*68+(rand()&3)*/, smokeparticletexture[rand()&7], true, 12, 128, 99, org[0], org[1], org[2], 0, 0, 0);
- particle(pt_bloodcloud, 251 /*68+(rand()&3)*/, smokeparticletexture[rand()&7], true, 10, 128, 99, org[0] + lhrandom(-4, 4), org[1] + lhrandom(-4, 4), org[2] + lhrandom(-4, 4), 0, 0, 0);
- particle(pt_bloodcloud, 251 /*68+(rand()&3)*/, smokeparticletexture[rand()&7], true, 8, 128, 99, org[0] + lhrandom(-4, 4), org[1] + lhrandom(-4, 4), org[2] + lhrandom(-4, 4), 0, 0, 0);
+ if (count > 100)
+ count = 100;
+ bloodcount += count;
+ while(bloodcount >= 10)
+ {
+ particle(pt_blood, 68+(rand()&3), smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64));
+ bloodcount -= 10;
+ }
}
void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
{
- int j;
- particle_t *p;
vec3_t diff;
vec3_t center;
vec3_t velscale;
if (!r_particles.value) return; // LordHavoc: particles are optional
+ if (!r_particles_bloodshowers.value) return;
+ if (!r_particles_blood.value) return;
VectorSubtract(maxs, mins, diff);
center[0] = (mins[0] + maxs[0]) * 0.5;
center[1] = (mins[1] + maxs[1]) * 0.5;
center[2] = (mins[2] + maxs[2]) * 0.5;
// FIXME: change velspeed back to 2.0x after fixing mod
- velscale[0] = velspeed * 0.5 / diff[0];
- velscale[1] = velspeed * 0.5 / diff[1];
- velscale[2] = velspeed * 0.5 / diff[2];
+ velscale[0] = velspeed * 2.0 / diff[0];
+ velscale[1] = velspeed * 2.0 / diff[1];
+ velscale[2] = velspeed * 2.0 / diff[2];
while (count--)
{
- ALLOCPARTICLE(p)
-
- p->texnum = smokeparticletexture[rand()&7];
- p->dynlight = true;
- p->scale = lhrandom(4, 6);
- p->alpha = 96 + (rand()&63);
- p->die = cl.time + 2;
- p->type = pt_bloodcloud;
- p->color = 251; //(rand()&3)+68;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = diff[j] * (float) (rand()%1024) * (1.0 / 1024.0) + mins[j];
- p->vel[j] = (p->org[j] - center[j]) * velscale[j];
- }
+ vec3_t org, vel;
+ org[0] = lhrandom(mins[0], maxs[0]);
+ org[1] = lhrandom(mins[1], maxs[1]);
+ org[2] = lhrandom(mins[2], maxs[2]);
+ vel[0] = (org[0] - center[0]) * velscale[0];
+ vel[1] = (org[1] - center[1]) * velscale[1];
+ vel[2] = (org[2] - center[2]) * velscale[2];
+ particle(pt_blood, 68+(rand()&3), smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0], vel[1], vel[2]);
}
}
void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel)
{
- int j;
- particle_t *p;
- vec3_t diff;
float t;
if (!r_particles.value) return; // LordHavoc: particles are optional
if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
- VectorSubtract(maxs, mins, diff);
-
while (count--)
- {
- ALLOCPARTICLE(p)
-
- p->texnum = particletexture;
- p->dynlight = false;
- p->scale = 6;
- p->alpha = 255;
- p->die = cl.time + 1 + (rand()&15)*0.0625;
- if (gravity)
- p->type = pt_grav;
- else
- p->type = pt_static;
- p->color = colorbase + (rand()&3);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = diff[j] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[j];
- if (randomvel)
- p->vel[j] = dir[j] + (rand()%randomvel)-(randomvel*0.5);
- else
- p->vel[j] = 0;
- }
- }
+ particle(gravity ? pt_grav : pt_static, colorbase + (rand()&3), particletexture, TPOLYTYPE_ALPHA, false, 2, 255, lhrandom(1, 2), 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0] + lhrandom(-randomvel, randomvel), dir[1] + lhrandom(-randomvel, randomvel), dir[2] + lhrandom(-randomvel, randomvel));
}
void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type)
{
- int i;
- particle_t *p;
- vec3_t diff;
- vec3_t org;
vec3_t vel;
float t, z;
if (!r_particles.value) return; // LordHavoc: particles are optional
}
if (t < 0 || t > 2) // sanity check
t = 2;
- t += cl.time;
- VectorSubtract(maxs, mins, diff);
-
- for (i=0 ; i<count ; i++)
+ switch(type)
{
- ALLOCPARTICLE(p)
-
- vel[0] = dir[0] + (rand()&31) - 16;
- vel[1] = dir[1] + (rand()&31) - 16;
- vel[2] = dir[2] + (rand()&63) - 32;
- org[0] = diff[0] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[0];
- org[1] = diff[1] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[1];
- org[2] = z;
-
- p->alpha = 255;
- p->die = t;
- if (type == 1)
+ case 0:
+ while(count--)
{
- p->scale = 2;
- p->texnum = particletexture;
- p->dynlight = false;
- p->type = pt_snow;
+ vel[0] = dir[0] + lhrandom(-16, 16);
+ vel[1] = dir[1] + lhrandom(-16, 16);
+ vel[2] = dir[2] + lhrandom(-32, 32);
+ particle4(pt_rain, colorbase + (rand()&3), rainparticletexture, TPOLYTYPE_ALPHA, true, 3, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2]);
}
- else // 0
+ break;
+ case 1:
+ while(count--)
{
- p->scale = 3;
- p->texnum = rainparticletexture;
- p->dynlight = true;
- p->type = pt_rain;
+ vel[0] = dir[0] + lhrandom(-16, 16);
+ vel[1] = dir[1] + lhrandom(-16, 16);
+ vel[2] = dir[2] + lhrandom(-32, 32);
+ particle4(pt_snow, colorbase + (rand()&3), particletexture, TPOLYTYPE_ALPHA, false, 2, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2]);
}
- p->color = colorbase + (rand()&3);
- VectorCopy(org, p->org);
- VectorCopy(vel, p->vel);
- VectorCopy(vel, p->vel2);
+ break;
+ default:
+ Host_Error("R_ParticleRain: unknown type %i (0 = rain, 1 = snow)\n", type);
}
}
+void R_FlameCube (vec3_t mins, vec3_t maxs, int count)
+{
+ float t;
+ if (!r_particles.value) return; // LordHavoc: particles are optional
+ if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
+ if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
+ if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
+
+ while (count--)
+ particle(pt_flame, 224 + (rand()&15), smokeparticletexture[rand()&7], TPOLYTYPE_ADD, false, 8, 255, 9999, 1.1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), lhrandom(-32, 32), lhrandom(-32, 32), lhrandom(-32, 64));
+}
+
+void R_Flames (vec3_t org, vec3_t vel, int count)
+{
+ if (!r_particles.value) return; // LordHavoc: particles are optional
+
+ while (count--)
+ particle(pt_flame, 224 + (rand()&15), smokeparticletexture[rand()&7], TPOLYTYPE_ADD, false, 8, 255, 9999, 1.1, org[0], org[1], org[2], vel[0] + lhrandom(-128, 128), vel[1] + lhrandom(-128, 128), vel[2] + lhrandom(-128, 128));
+}
+
+
/*
===============
===============
*/
-void R_LavaSplash (vec3_t org)
+void R_LavaSplash (vec3_t origin)
{
int i, j;
- particle_t *p;
float vel;
- vec3_t dir;
+ vec3_t dir, org;
if (!r_particles.value) return; // LordHavoc: particles are optional
for (i=-128 ; i<128 ; i+=16)
+ {
for (j=-128 ; j<128 ; j+=16)
{
- ALLOCPARTICLE(p)
-
- p->texnum = particletexture;
- p->dynlight = false;
- p->scale = 10;
- p->alpha = 128;
- p->die = cl.time + 2 + (rand()&31) * 0.02;
- p->color = 224 + (rand()&7);
- p->type = pt_grav;
-
- dir[0] = j + (rand()&7);
- dir[1] = i + (rand()&7);
+ dir[0] = j + lhrandom(0, 8);
+ dir[1] = i + lhrandom(0, 8);
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);
+ org[0] = origin[0] + dir[0];
+ org[1] = origin[1] + dir[1];
+ org[2] = origin[2] + lhrandom(0, 64);
+ vel = lhrandom(50, 120) / VectorLength(dir); // normalize and scale
+ particle(pt_lavasplash, 224 + (rand()&7), particletexture, TPOLYTYPE_ALPHA, false, 7, 255, 9999, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel);
+// particle(pt_lavasplash, 224 + (rand()&7), particletexture, TPOLYTYPE_ALPHA, false, 7, 255, 9999, 0, origin[0] + i, origin[1] + j, origin[2] + lhrandom(0, 63), i * lhrandom(0.125, 0.25), j * lhrandom(0.125, 0.25), lhrandom(64, 128));
}
+ }
}
/*
void R_TeleportSplash (vec3_t org)
{
int i, j, k;
- particle_t *p;
if (!r_particles.value) return; // LordHavoc: particles are optional
for (i=-16 ; i<16 ; i+=8)
for (j=-16 ; j<16 ; j+=8)
for (k=-24 ; k<32 ; k+=8)
- {
- ALLOCPARTICLE(p)
-
- p->texnum = particletexture;
- p->dynlight = false;
- p->scale = 1;
- p->alpha = lhrandom(32,128);
- p->die = cl.time + 5;
- p->color = 254;
- p->type = pt_fade;
-
- p->org[0] = org[0] + i + (rand()&7);
- p->org[1] = org[1] + j + (rand()&7);
- p->org[2] = org[2] + k + (rand()&7);
-
- p->vel[0] = i*2 + (rand()%25) - 12;
- p->vel[1] = j*2 + (rand()%25) - 12;
- p->vel[2] = k*2 + (rand()%25) - 12 + 40;
- }
+ particle(pt_fade, 254, particletexture, TPOLYTYPE_ADD, false, 1, lhrandom(64, 128), 9999, 0, org[0] + i + lhrandom(0, 8), org[1] + j + lhrandom(0, 8), org[2] + k + lhrandom(0, 8), i*2 + lhrandom(-12.5, 12.5), j*2 + lhrandom(-12.5, 12.5), k*2 + lhrandom(27.5, 52.5));
}
void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
{
- vec3_t vec;
- float len, dec = 0, t, nt, speed;
- int j, contents, bubbles;
- particle_t *p;
+ vec3_t vec, dir, vel;
+ float len, dec = 0, speed;
+ int contents, bubbles, polytype;
+ double t;
if (!r_particles.value) return; // LordHavoc: particles are optional
- t = cl.oldtime;
- nt = cl.time;
- if (ent->trail_leftover < 0)
- ent->trail_leftover = 0;
- t += ent->trail_leftover;
- ent->trail_leftover -= (cl.time - cl.oldtime);
+ VectorSubtract(end, start, dir);
+ VectorNormalize(dir);
+
+ /*
+ if (type == 0) // rocket glow
+ particle(pt_glow, 254, particletexture, TPOLYTYPE_ADD, false, 10, 160, 9999, 0, start[0] - 12 * dir[0], start[1] - 12 * dir[1], start[2] - 12 * dir[2], 0, 0, 0);
+ */
+
+ t = ent->trail_time;
if (t >= cl.time)
- return;
+ return; // no particles to spawn this frame (sparse trail)
- contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
- if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
- return;
+ if (t < cl.oldtime)
+ t = cl.oldtime;
VectorSubtract (end, start, vec);
len = VectorNormalizeLength (vec);
if (len <= 0.01f)
+ {
+ // advance the trail time
+ ent->trail_time = cl.time;
return;
- speed = len / (nt - t);
+ }
+ speed = len / (cl.time - cl.oldtime);
+ VectorScale(vec, speed, vel);
- bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME);
+ // advance into this frame to reach the first puff location
+ dec = t - cl.oldtime;
+ dec *= speed;
+ VectorMA(start, dec, vec, start);
- while (t < nt)
+ contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
+ if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
{
- ALLOCPARTICLE(p)
-
- p->vel[0] = p->vel[1] = p->vel[2] = 0;
- p->die = cl.time + 2;
+ // advance the trail time
+ ent->trail_time = cl.time;
+ return;
+ }
+
+ bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME);
+
+ polytype = TPOLYTYPE_ALPHA;
+ if (ent->effects & EF_ADDITIVE)
+ polytype = TPOLYTYPE_ADD;
+ while (t < cl.time)
+ {
switch (type)
{
case 0: // rocket trail
- case 1: // grenade trail
- if (bubbles)
+ if (!r_particles_smoke.value)
+ dec = cl.time - t;
+ else if (bubbles && r_particles_bubbles.value)
{
- dec = type == 0 ? 0.01f : 0.02f;
- p->texnum = bubbleparticletexture;
- p->dynlight = false;
- p->scale = lhrandom(1,2);
- p->alpha = 255;
- p->color = 254;
- p->type = pt_bubble;
- p->die = cl.time + 2;
- for (j=0 ; j<3 ; j++)
- {
- p->vel[j] = (rand()&31)-16;
- p->org[j] = start[j] + ((rand()&3)-2);
- }
+ dec = 0.01f;
+ particle(pt_bubble, 254, bubbleparticletexture, polytype, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16));
+ particle(pt_bubble, 254, bubbleparticletexture, polytype, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16));
+ particle(pt_smoke, 254, smokeparticletexture[rand()&7], polytype, false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
}
else
{
- dec = type == 0 ? 0.02f : 0.04f;
- p->texnum = smokeparticletexture[rand()&7];
- p->dynlight = true;
- p->scale = lhrandom(4, 8);
- p->alpha = 160; //128 + (rand()&63);
- p->color = 254;
- p->type = pt_smoke;
- p->die = cl.time + 10000;
- VectorCopy(start, p->org);
- /*
- if (type == 0)
- {
- particle(pt_fallfadespark, 0x68 + (rand() & 7), particletexture, false, 1, lhrandom(64, 128), 5, start[0], start[1], start[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64));
- particle(pt_fallfadespark, 0x68 + (rand() & 7), particletexture, false, 1, lhrandom(64, 128), 5, start[0], start[1], start[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64));
- particle(pt_fallfadespark, 0x68 + (rand() & 7), particletexture, false, 1, lhrandom(64, 128), 5, start[0], start[1], start[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64));
- particle(pt_fallfadespark, 0x68 + (rand() & 7), particletexture, false, 1, lhrandom(64, 128), 5, start[0], start[1], start[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64));
- }
- */
+ dec = 0.01f;
+ particle(pt_smoke, 12, smokeparticletexture[rand()&7], polytype, true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
+// particle(pt_spark, 0x68 + (rand() & 7), particletexture, TPOLYTYPE_ADD, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.25, lhrandom(-64, 64) - vel[1] * 0.25, lhrandom(-64, 64) - vel[2] * 0.25);
+// particle(pt_spark, 0x68 + (rand() & 7), particletexture, TPOLYTYPE_ADD, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.25, lhrandom(-64, 64) - vel[1] * 0.25, lhrandom(-64, 64) - vel[2] * 0.25);
+// particle(pt_spark, 0x68 + (rand() & 7), particletexture, TPOLYTYPE_ADD, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.25, lhrandom(-64, 64) - vel[1] * 0.25, lhrandom(-64, 64) - vel[2] * 0.25);
+// particle(pt_spark, 0x68 + (rand() & 7), particletexture, TPOLYTYPE_ADD, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.25, lhrandom(-64, 64) - vel[1] * 0.25, lhrandom(-64, 64) - vel[2] * 0.25);
}
break;
- /*
- case 1: // smoke smoke
- dec = 0.016f;
- p->texnum = smokeparticletexture;
- p->dynlight = true;
- p->scale = lhrandom(6,9);
- p->alpha = 64;
- if (r_smokecolor.value)
- p->color = r_smokecolor.value;
+ case 1: // grenade trail
+ // FIXME: make it gradually stop smoking
+ if (!r_particles_smoke.value)
+ dec = cl.time - t;
+ else if (bubbles && r_particles_bubbles.value)
+ {
+ dec = 0.02f;
+ particle(pt_bubble, 254, bubbleparticletexture, polytype, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16));
+ particle(pt_bubble, 254, bubbleparticletexture, polytype, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16));
+ particle(pt_smoke, 254, smokeparticletexture[rand()&7], polytype, false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
+ }
else
- p->color = (rand()&3)+12;
- p->type = pt_smoke;
- p->die = cl.time + 1;
- VectorCopy(start, p->org);
+ {
+ dec = 0.02f;
+ particle(pt_smoke, 8, smokeparticletexture[rand()&7], polytype, true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
+ }
break;
- */
+
case 2: // blood
+ if (!r_particles_blood.value)
+ dec = cl.time - t;
+ else
+ {
+ dec = 0.2f;
+ particle(pt_blood, 67+(rand()&3), smokeparticletexture[rand()&7], polytype, true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64));
+ }
+ break;
+
case 4: // slight blood
- dec = 0.025f;
- p->texnum = smokeparticletexture[rand()&7];
- p->dynlight = true;
- p->scale = lhrandom(4, 6);
- p->alpha = type == 4 ? 192 : 255;
- p->color = 247; //(rand()&3)+68;
- p->type = pt_bloodcloud;
- p->die = cl.time + 9999;
- for (j=0 ; j<3 ; j++)
+ if (!r_particles_blood.value)
+ dec = cl.time - t;
+ else
{
- p->vel[j] = (rand()&15)-8;
- p->org[j] = start[j] + ((rand()&3)-2);
+ dec = 0.3f;
+ particle(pt_blood, 67+(rand()&3), smokeparticletexture[rand()&7], polytype, true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64));
}
break;
- case 3:
- case 5: // tracer
+ case 3: // green tracer
dec = 0.02f;
- p->texnum = smokeparticletexture[rand()&7];
- p->dynlight = false;
- p->scale = 4;
- p->alpha = 64 + (rand()&31);
- p->color = type == 3 ? 56 : 234;
- p->type = pt_fade;
- p->die = cl.time + 10000;
- VectorCopy(start, p->org);
+ particle(pt_fade, 56, smokeparticletexture[rand()&7], polytype, false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
+ break;
+
+ case 5: // flame tracer
+ dec = 0.02f;
+ particle(pt_fade, 234, smokeparticletexture[rand()&7], polytype, false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
break;
case 6: // voor trail
dec = 0.05f; // sparse trail
- p->texnum = smokeparticletexture[rand()&7];
- p->dynlight = false;
- p->scale = lhrandom(3, 5);
- p->alpha = 255;
- p->color = 9*16 + 8 + (rand()&3);
- p->type = pt_fade;
- p->die = cl.time + 2;
- for (j=0 ; j<3 ; j++)
- {
- p->vel[j] = (rand()&15)-8;
- p->org[j] = start[j] + ((rand()&3)-2);
- }
+ particle(pt_fade, 152 + (rand()&3), smokeparticletexture[rand()&7], polytype, false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
break;
case 7: // Nehahra smoke tracer
- dec = 0.14f;
- p->texnum = smokeparticletexture[rand()&7];
- p->dynlight = true;
- p->scale = lhrandom(8, 12);
- p->alpha = 64;
- p->color = (rand()&3)+12;
- p->type = pt_smoke;
- p->die = cl.time + 10000;
- for (j=0 ; j<3 ; j++)
- p->org[j] = start[j] + ((rand()&3)-2);
+ if (!r_particles_smoke.value)
+ dec = cl.time - t;
+ else
+ {
+ dec = 0.14f;
+ particle(pt_smoke, 12, smokeparticletexture[rand()&7], polytype, true, 10, 64, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
+ }
break;
}
-
+
+ // advance to next time and position
t += dec;
dec *= speed;
VectorMA (start, dec, vec, start);
}
- ent->trail_leftover = t - cl.time;
+ ent->trail_time = t;
}
void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
vec3_t vec;
int len;
if (!r_particles.value) return; // LordHavoc: particles are optional
+ if (!r_particles_smoke.value) return;
VectorSubtract (end, start, vec);
len = (int) (VectorNormalizeLength (vec) * (1.0f / 3.0f));
VectorScale(vec, 3, vec);
while (len--)
{
- particle(pt_smoke, color, particletexture, false, 8, 192, 99, start[0], start[1], start[2], 0, 0, 0);
+ particle(pt_smoke, color, particletexture, TPOLYTYPE_ALPHA, false, 8, 192, 9999, 0, start[0], start[1], start[2], 0, 0, 0);
VectorAdd (start, vec, start);
}
}
return;
frametime = cl.time - cl.oldtime;
+ if (!frametime)
+ return; // if absolutely still, don't update particles
gravity = frametime * sv_gravity.value;
dvel = 1+4*frametime;
p->org[0] += p->vel[0]*frametime;
p->org[1] += p->vel[1]*frametime;
p->org[2] += p->vel[2]*frametime;
+ if (p->bounce)
+ {
+ vec3_t normal;
+ float dist;
+ if (TraceLine(p->oldorg, p->org, v, normal) < 1)
+ {
+ VectorCopy(v, p->org);
+ if (p->bounce < 0)
+ {
+ byte *color24 = (byte *) &d_8to24table[(int)p->color];
+ R_Decal(v, p->tex, p->scale, color24[0], color24[1], color24[2], p->alpha);
+ p->die = -1;
+ freeparticles[j++] = p;
+ continue;
+ /*
+ VectorClear(p->vel);
+ p->type = pt_decal;
+ // have to negate the direction (why?)
+ VectorNegate(normal, p->direction);
+ VectorVectors(p->direction, p->decalright, p->decalup);
+ VectorSubtract(p->org, p->direction, p->org); // push off the surface a bit so it doesn't flicker
+ p->bounce = 0;
+ p->time2 = cl.time + 30;
+ */
+ }
+ else
+ {
+ dist = DotProduct(p->vel, normal) * -p->bounce;
+ VectorMAQuick(p->vel, dist, normal, p->vel);
+ if (DotProduct(p->vel, p->vel) < 0.03)
+ VectorClear(p->vel);
+ }
+ }
+ }
switch (p->type)
{
case pt_blob2:
p->vel[0] *= dvel;
p->vel[1] *= dvel;
+ p->alpha -= frametime * 256;
+ if (p->alpha < 1)
+ p->die = -1;
break;
case pt_grav:
p->vel[2] -= gravity;
break;
+ case pt_slowgrav:
+ p->vel[2] -= gravity * 0.05;
+ break;
+ case pt_lavasplash:
+ p->vel[2] -= gravity * 0.05;
+ p->alpha -= frametime * 192;
+ if (p->alpha < 1)
+ p->die = -1;
+ break;
case pt_snow:
if (cl.time > p->time2)
{
p->vel[1] = (rand()&63)-32 + p->vel2[1];
p->vel[2] = (rand()&63)-32 + p->vel2[2];
}
+ a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+ if (a != CONTENTS_EMPTY && a != CONTENTS_SKY)
+ {
+ vec3_t normal;
+ if (a == CONTENTS_SOLID && Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents == CONTENTS_SOLID)
+ break; // still in solid
+ p->die = cl.time + 1000;
+ p->vel[0] = p->vel[1] = p->vel[2] = 0;
+ switch (a)
+ {
+ case CONTENTS_LAVA:
+ case CONTENTS_SLIME:
+ p->tex = smokeparticletexture[rand()&7];
+ p->type = pt_steam;
+ p->alpha = 96;
+ p->scale = 5;
+ p->vel[2] = 96;
+ break;
+ case CONTENTS_WATER:
+ p->tex = smokeparticletexture[rand()&7];
+ p->type = pt_splash;
+ p->alpha = 96;
+ p->scale = 5;
+ p->vel[2] = 96;
+ break;
+ default: // CONTENTS_SOLID and any others
+ TraceLine(p->oldorg, p->org, v, normal);
+ VectorCopy(v, p->org);
+ p->tex = smokeparticletexture[rand()&7];
+ p->type = pt_fade;
+ VectorClear(p->vel);
+ break;
+ }
+ }
break;
- case pt_bloodcloud:
-// if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
-// {
-// p->die = -1;
-// break;
-// }
- p->scale += frametime * 16;
- p->alpha -= frametime * 512;
+ case pt_blood:
+ if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
+ {
+ p->die = -1;
+ break;
+ }
+ p->vel[2] -= gravity * 0.5;
break;
- case pt_fallfadespark:
- p->alpha -= frametime * 256;
+ case pt_spark:
+ p->alpha -= frametime * 512;
p->vel[2] -= gravity;
+ if (p->alpha < 1)
+ p->die = -1;
break;
case pt_fade:
p->alpha -= frametime * 512;
+ if (p->alpha < 1)
+ p->die = -1;
break;
case pt_bubble:
a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
if (a != CONTENTS_WATER && a != CONTENTS_SLIME)
{
- p->texnum = smokeparticletexture[rand()&7];
- p->type = pt_splash;
- p->alpha = 96;
- p->scale = 5;
+ p->tex = smokeparticletexture[rand()&7];
+ p->type = pt_splashpuff;
+ p->scale = 4;
p->vel[0] = p->vel[1] = p->vel[2] = 0;
- p->die = cl.time + 1000;
-// p->die = -1;
+ break;
}
p->vel[2] += gravity * 0.25;
p->vel[0] *= (1 - (frametime * 0.0625));
p->vel[1] += lhrandom(-32,32);
p->vel[2] += lhrandom(-32,32);
}
- p->alpha -= frametime * 64;
+ p->alpha -= frametime * 256;
+ if (p->alpha < 1)
+ p->die = -1;
break;
-// LordHavoc: for smoke trails
- case pt_smoke:
+ case pt_bulletsmoke:
p->scale += frametime * 16;
- p->alpha -= frametime * 256;
+ p->alpha -= frametime * 1024;
+ p->vel[2] += gravity * 0.05;
+ if (p->alpha < 1)
+ p->die = -1;
break;
- case pt_smokecloud:
- p->scale += frametime * 64;
- p->alpha -= frametime * 256;
+ case pt_smoke:
+ p->scale += frametime * 32;
+ p->alpha -= frametime * 512;
+ p->vel[2] += gravity * 0.05;
+ if (p->alpha < 1)
+ p->die = -1;
break;
- case pt_splash:
- p->scale += frametime * 24;
+ case pt_steam:
+ p->scale += frametime * 48;
p->alpha -= frametime * 512;
+ p->vel[2] += gravity * 0.05;
+ if (p->alpha < 1)
+ p->die = -1;
+ break;
+ case pt_splashpuff:
+// p->scale += frametime * 24;
+ p->alpha -= frametime * 1024;
+ if (p->alpha < 1)
+ p->die = -1;
break;
case pt_rain:
a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
if (a == CONTENTS_SOLID && Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents == CONTENTS_SOLID)
break; // still in solid
p->die = cl.time + 1000;
+ p->vel[0] = p->vel[1] = p->vel[2] = 0;
switch (a)
{
case CONTENTS_LAVA:
case CONTENTS_SLIME:
- p->texnum = smokeparticletexture[rand()&7];
- p->type = pt_smokecloud;
- p->alpha = 64;
+ p->tex = smokeparticletexture[rand()&7];
+ p->type = pt_steam;
+ p->scale = 3;
p->vel[2] = 96;
break;
case CONTENTS_WATER:
- p->texnum = smokeparticletexture[rand()&7];
- p->type = pt_splash;
- p->alpha = 96;
- p->scale = 5;
- p->vel[0] = p->vel[1] = p->vel[2] = 0;
-// p->texnum = bubbleparticletexture;
-// p->type = pt_bubble;
-// p->vel[2] *= 0.1;
+ p->tex = smokeparticletexture[rand()&7];
+ p->type = pt_splashpuff;
+ p->scale = 4;
break;
default: // CONTENTS_SOLID and any others
TraceLine(p->oldorg, p->org, v, normal);
VectorCopy(v, p->org);
- p->texnum = smokeparticletexture[rand()&7];
- p->type = pt_splash;
- p->alpha = 96;
- p->scale = 5;
- p->vel[0] = p->vel[1] = p->vel[2] = 0;
- p->die = cl.time + 1000;
+ p->tex = smokeparticletexture[rand()&7];
+ p->type = pt_splashpuff;
+ p->scale = 4;
break;
}
}
break;
case pt_flame:
p->alpha -= frametime * 512;
+ p->vel[2] += gravity;
+// p->scale -= frametime * 16;
+ if (p->alpha < 16)
+ p->die = -1;
break;
+ /*
case pt_flamingdebris:
if (cl.time >= p->time2)
{
p->time2 = cl.time + 0.01;
- particle2(pt_flame, p->color, particletexture, false, 4, p->alpha, 999, p->org, 0, 50);
+ particle(pt_flame, p->color, particletexture, TPOLYTYPE_ADD, false, 4, p->alpha, 9999, 0, org[0], org[1], org[2], lhrandom(-50, 50), lhrandom(-50, 50), lhrandom(-50, 50));
}
p->alpha -= frametime * 512;
p->vel[2] -= gravity * 0.5f;
if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
p->die = -1;
+ if (p->alpha < 1)
+ p->die = -1;
break;
case pt_smokingdebris:
if (cl.time >= p->time2)
{
p->time2 = cl.time + 0.01;
- particle2(pt_flame, 15, smokeparticletexture[rand()&7], false, 4, p->alpha, 999, p->org, 0, 50);
+ particle2(pt_flame, 15, smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, false, 4, p->alpha, 9999, 0, org[0], org[1], org[2], lhrandom(-50, 50), lhrandom(-50, 50), lhrandom(-50, 50));
}
p->alpha -= frametime * 512;
p->vel[2] -= gravity * 0.5f;
if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
p->die = -1;
+ if (p->alpha < 1)
+ p->die = -1;
break;
case pt_flamefall:
p->alpha -= frametime * 512;
p->vel[2] -= gravity * 0.5f;
+ if (p->alpha < 1)
+ p->die = -1;
break;
- }
-
- // LordHavoc: most particles did this check anyway, consistency...
- if (p->alpha < 1)
+ */
+ /*
+ case pt_decal:
+ if (cl.time > p->time2)
+ {
+ p->alpha -= frametime * 256;
+ if (p->alpha < 1)
+ p->die = -1;
+ }
+ if (p->alpha < 64)
+ p->die = -1;
+ break;
+ */
+ case pt_oneframe:
+ if (p->time2)
+ p->die = -1;
+ p->time2 = 1;
+ break;
+ default:
+ printf("unknown particle type %i\n", p->type);
p->die = -1;
+ break;
+ }
// LordHavoc: immediate removal of unnecessary particles (must be done to ensure compactor below operates properly in all cases)
if (p->die < cl.time)
numparticles = activeparticles;
}
-void R_CompleteLightPoint (vec3_t color, vec3_t p);
-
void R_DrawParticles (void)
{
particle_t *p;
- int i, r,g,b,a, dynlight;
+ int i, dynamiclight, staticlight, r, g, b;
+ byte br, bg, bb, ba;
float scale, scale2, minparticledist;
byte *color24;
- vec3_t up, right, uprightangles, forward2, up2, right2, tempcolor;
+ vec3_t uprightangles, up2, right2, tempcolor, corner;
// LordHavoc: early out condition
if ((!numparticles) || (!r_drawparticles.value))
return;
- dynlight = r_dynamicparticles.value;
+ staticlight = dynamiclight = r_particles_lighting.value;
if (!r_dynamic.value)
- dynlight = 0;
+ dynamiclight = 0;
c_particles += numparticles;
- VectorScale (vup, 1.5, up);
- VectorScale (vright, 1.5, right);
-
uprightangles[0] = 0;
uprightangles[1] = r_refdef.viewangles[1];
uprightangles[2] = 0;
- AngleVectors (uprightangles, forward2, right2, up2);
+ AngleVectors (uprightangles, NULL, right2, up2);
minparticledist = DotProduct(r_refdef.vieworg, vpn) + 16.0f;
if (DotProduct(p->org, vpn) < minparticledist)
continue;
+ /*
+ if (p->type == pt_decal)
+ {
+ VectorSubtract(p->org, r_refdef.vieworg, v);
+ if (DotProduct(p->direction, v) < 0)
+ continue;
+ }
+ */
+
color24 = (byte *) &d_8to24table[(int)p->color];
r = color24[0];
g = color24[1];
b = color24[2];
- a = p->alpha;
- if (dynlight && (p->dynlight || dynlight >= 2)) // LordHavoc: only light blood and smoke
+ if (staticlight && (p->dynlight || staticlight >= 2)) // LordHavoc: only light blood and smoke
{
- R_CompleteLightPoint(tempcolor, p->org);
+ R_CompleteLightPoint(tempcolor, p->org, dynamiclight);
r = (r * (int) tempcolor[0]) >> 7;
g = (g * (int) tempcolor[1]) >> 7;
b = (b * (int) tempcolor[2]) >> 7;
}
- transpolybegin(p->texnum, 0, p->texnum, TPOLYTYPE_ALPHA);
- scale = p->scale * -0.5;scale2 = p->scale * 0.5;
- if (p->texnum == rainparticletexture) // rain streak
+ br = (byte) min(r, 255);
+ bg = (byte) min(g, 255);
+ bb = (byte) min(b, 255);
+ ba = (byte) p->alpha;
+ transpolybegin(R_GetTexture(p->tex), 0, R_GetTexture(p->tex), p->rendermode);
+ scale = p->scale * -0.5;scale2 = p->scale;
+ /*
+ if (p->type == pt_decal)
+ {
+ corner[0] = p->org[0] + p->decalup[0]*scale + p->decalright[0]*scale;
+ corner[1] = p->org[1] + p->decalup[1]*scale + p->decalright[1]*scale;
+ corner[2] = p->org[2] + p->decalup[2]*scale + p->decalright[2]*scale;
+ transpolyvertub(corner[0] , corner[1] , corner[2] , 0,1,br,bg,bb,ba);
+ transpolyvertub(corner[0] + p->decalup[0]*scale2 , corner[1] + p->decalup[1]*scale2 , corner[2] + p->decalup[2]*scale2 , 0,0,br,bg,bb,ba);
+ transpolyvertub(corner[0] + p->decalup[0]*scale2 + p->decalright[0]*scale2, corner[1] + p->decalup[1]*scale2 + p->decalright[1]*scale2, corner[2] + p->decalup[2]*scale2 + p->decalright[2]*scale2, 1,0,br,bg,bb,ba);
+ transpolyvertub(corner[0] + p->decalright[0]*scale2, corner[1] + p->decalright[1]*scale2, corner[2] + p->decalright[2]*scale2, 1,1,br,bg,bb,ba);
+ }
+ else*/ if (p->tex == rainparticletexture) // rain streak
{
- transpolyvert(p->org[0] + up2[0]*scale + right2[0]*scale , p->org[1] + up2[1]*scale + right2[1]*scale , p->org[2] + up2[2]*scale + right2[2]*scale , 0,1,r,g,b,a);
- transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale , p->org[1] + up2[1]*scale2 + right2[1]*scale , p->org[2] + up2[2]*scale2 + right2[2]*scale , 0,0,r,g,b,a);
- transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale2, p->org[1] + up2[1]*scale2 + right2[1]*scale2, p->org[2] + up2[2]*scale2 + right2[2]*scale2, 1,0,r,g,b,a);
- transpolyvert(p->org[0] + up2[0]*scale + right2[0]*scale2, p->org[1] + up2[1]*scale + right2[1]*scale2, p->org[2] + up2[2]*scale + right2[2]*scale2, 1,1,r,g,b,a);
+ corner[0] = p->org[0] + up2[0]*scale + right2[0]*scale;
+ corner[1] = p->org[1] + up2[1]*scale + right2[1]*scale;
+ corner[2] = p->org[2] + up2[2]*scale + right2[2]*scale;
+ transpolyvertub(corner[0] , corner[1] , corner[2] , 0,1,br,bg,bb,ba);
+ transpolyvertub(corner[0] + up2[0]*scale2 , corner[1] + up2[1]*scale2 , corner[2] + up2[2]*scale2 , 0,0,br,bg,bb,ba);
+ transpolyvertub(corner[0] + up2[0]*scale2 + right2[0]*scale2, corner[1] + up2[1]*scale2 + right2[1]*scale2, corner[2] + up2[2]*scale2 + right2[2]*scale2, 1,0,br,bg,bb,ba);
+ transpolyvertub(corner[0] + right2[0]*scale2, corner[1] + right2[1]*scale2, corner[2] + right2[2]*scale2, 1,1,br,bg,bb,ba);
}
else
{
- transpolyvert(p->org[0] + up[0]*scale + right[0]*scale , p->org[1] + up[1]*scale + right[1]*scale , p->org[2] + up[2]*scale + right[2]*scale , 0,1,r,g,b,a);
- transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale , 0,0,r,g,b,a);
- transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale2, p->org[1] + up[1]*scale2 + right[1]*scale2, p->org[2] + up[2]*scale2 + right[2]*scale2, 1,0,r,g,b,a);
- transpolyvert(p->org[0] + up[0]*scale + right[0]*scale2, p->org[1] + up[1]*scale + right[1]*scale2, p->org[2] + up[2]*scale + right[2]*scale2, 1,1,r,g,b,a);
+ corner[0] = p->org[0] + vup[0]*scale + vright[0]*scale;
+ corner[1] = p->org[1] + vup[1]*scale + vright[1]*scale;
+ corner[2] = p->org[2] + vup[2]*scale + vright[2]*scale;
+ transpolyvertub(corner[0] , corner[1] , corner[2] , 0,1,br,bg,bb,ba);
+ transpolyvertub(corner[0] + vup[0]*scale2 , corner[1] + vup[1]*scale2 , corner[2] + vup[2]*scale2 , 0,0,br,bg,bb,ba);
+ transpolyvertub(corner[0] + vup[0]*scale2 + vright[0]*scale2, corner[1] + vup[1]*scale2 + vright[1]*scale2, corner[2] + vup[2]*scale2 + vright[2]*scale2, 1,0,br,bg,bb,ba);
+ transpolyvertub(corner[0] + vright[0]*scale2, corner[1] + vright[1]*scale2, corner[2] + vright[2]*scale2, 1,1,br,bg,bb,ba);
}
transpolyend();
}