1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 //
21 // cg_particles.c
22 //
23
24 #include "cg_local.h"
25
26 static cgParticle_t *cg_freeParticles;
27 static cgParticle_t cg_particleHeadNode, cg_particleList[MAX_PARTICLES];
28 static int cg_numParticles;
29
30 /*
31 =============================================================================
32
33 PARTICLE MATERIAL RANDOMIZING
34
35 =============================================================================
36 */
37
pRandBloodDrip(void)38 int pRandBloodDrip (void) { return PT_BLDDRIP01 + (rand()&1); }
pRandGrnBloodDrip(void)39 int pRandGrnBloodDrip (void){ return PT_BLDDRIP01_GRN + (rand()&1); }
pRandBloodMark(void)40 int pRandBloodMark (void) { return PT_BLOOD + (rand()%6); }
pRandGrnBloodMark(void)41 int pRandGrnBloodMark (void){ return PT_GRNBLOOD + (rand()%6); }
pRandSmoke(void)42 int pRandSmoke (void) { return PT_SMOKE + (rand()&1); }
pRandGlowSmoke(void)43 int pRandGlowSmoke (void) { return PT_SMOKEGLOW + (rand()&1); }
pRandEmbers(void)44 int pRandEmbers (void) { return PT_EMBERS1 + (rand()%3); }
pRandFire(void)45 int pRandFire (void) { return PT_FIRE1 + (rand()&3); }
46
47 /*
48 =============================================================================
49
50 PARTICLE MANAGEMENT
51
52 =============================================================================
53 */
54
55 /*
56 ===============
57 CG_AllocParticle
58 ===============
59 */
CG_AllocParticle(void)60 static cgParticle_t *CG_AllocParticle (void)
61 {
62 cgParticle_t *p;
63
64 // Take a free particle spot if possible, otherwise steal the oldest one
65 if (cg_freeParticles && cg_numParticles+1 < cg_particleMax->intVal) {
66 p = cg_freeParticles;
67 cg_freeParticles = p->next;
68 }
69 else {
70 p = cg_particleHeadNode.prev;
71 p->prev->next = p->next;
72 p->next->prev = p->prev;
73
74 cg_numParticles--;
75 }
76
77 // Move to the beginning of the list
78 p->prev = &cg_particleHeadNode;
79 p->next = cg_particleHeadNode.next;
80 p->next->prev = p;
81 p->prev->next = p;
82
83 cg_numParticles++;
84 return p;
85 }
86
87
88 /*
89 ===============
90 CG_FreeParticle
91 ===============
92 */
CG_FreeParticle(cgParticle_t * p)93 static inline void CG_FreeParticle (cgParticle_t *p)
94 {
95 // Remove from linked active list
96 p->prev->next = p->next;
97 p->next->prev = p->prev;
98
99 // Insert into linked free list
100 p->next = cg_freeParticles;
101 cg_freeParticles = p;
102
103 cg_numParticles--;
104 }
105
106
107 /*
108 ===============
109 CG_SpawnParticle
110
111 FIXME: JESUS H FUNCTION PARAMATERS
112 ===============
113 */
CG_SpawnParticle(float org0,float org1,float org2,float angle0,float angle1,float angle2,float vel0,float vel1,float vel2,float accel0,float accel1,float accel2,float red,float green,float blue,float redVel,float greenVel,float blueVel,float alpha,float alphaVel,float size,float sizeVel,uint32 type,uint32 flags,void (* think)(struct cgParticle_s * p,vec3_t org,vec3_t angle,vec4_t color,float * size,float * orient,float * time),qBool thinkNext,byte style,float orient)114 void CG_SpawnParticle (float org0, float org1, float org2,
115 float angle0, float angle1, float angle2,
116 float vel0, float vel1, float vel2,
117 float accel0, float accel1, float accel2,
118 float red, float green, float blue,
119 float redVel, float greenVel, float blueVel,
120 float alpha, float alphaVel,
121 float size, float sizeVel,
122 uint32 type, uint32 flags,
123 void (*think)(struct cgParticle_s *p, vec3_t org, vec3_t angle, vec4_t color, float *size, float *orient, float *time),
124 qBool thinkNext,
125 byte style,
126 float orient)
127 {
128 cgParticle_t *p = NULL;
129
130 p = CG_AllocParticle ();
131 p->time = (float)cg.realTime;
132
133 Vec3Set (p->org, org0, org1, org2);
134 Vec3Copy (p->org, p->oldOrigin);
135
136 Vec3Set (p->angle, angle0, angle1, angle2);
137 Vec3Set (p->vel, vel0, vel1, vel2);
138 Vec3Set (p->accel, accel0, accel1, accel2);
139
140 Vec4Set (p->color, red, green, blue, alpha);
141 Vec4Set (p->colorVel, redVel, greenVel, blueVel, alphaVel);
142
143 p->shader = cgMedia.particleTable[type%PT_PICTOTAL];
144 p->style = style;
145 p->flags = flags;
146
147 p->size = size;
148 p->sizeVel = sizeVel;
149
150 if (think)
151 p->think = think;
152 else
153 p->think = NULL;
154
155 p->thinkNext = thinkNext;
156
157 p->orient = orient;
158 }
159
160
161 /*
162 ===============
163 CG_ClearParticles
164 ===============
165 */
CG_ClearParticles(void)166 void CG_ClearParticles (void)
167 {
168 int i;
169
170 // Link particles
171 cg_freeParticles = &cg_particleList[0];
172 cg_particleHeadNode.prev = &cg_particleHeadNode;
173 cg_particleHeadNode.next = &cg_particleHeadNode;
174 for (i=0 ; i<MAX_PARTICLES ; i++) {
175 if (i < MAX_PARTICLES-1)
176 cg_particleList[i].next = &cg_particleList[i+1];
177
178 // Store static poly info
179 cg_particleList[i].outPoly.numVerts = 4;
180 cg_particleList[i].outPoly.colors = cg_particleList[i].outColor;
181 cg_particleList[i].outPoly.texCoords = cg_particleList[i].outCoords;
182 cg_particleList[i].outPoly.vertices = cg_particleList[i].outVertices;
183 cg_particleList[i].outPoly.shaderTime = 0;
184 }
185
186 cg_particleList[MAX_PARTICLES-1].next = NULL;
187 }
188
189
190 /*
191 ===============
192 CG_AddParticles
193 ===============
194 */
CG_AddParticles(void)195 void CG_AddParticles (void)
196 {
197 cgParticle_t *p, *next, *hNode;
198 vec3_t org, temp;
199 vec4_t color;
200 float size, orient;
201 float time, time2, dist;
202 int i, j, pointBits;
203 float lightest;
204 vec3_t shade;
205 float scale;
206 vec3_t p_upVec, p_rtVec;
207 vec3_t a_upVec, a_rtVec;
208 vec3_t point, width, move;
209 bvec4_t outColor;
210 vec3_t delta, vdelta;
211 int num;
212
213 CG_AddMapFXToList ();
214 CG_AddSustains ();
215 if (!cl_add_particles->intVal)
216 return;
217
218 Vec3Scale (cg.refDef.viewAxis[2], 0.75f, p_upVec);
219 Vec3Scale (cg.refDef.rightVec, 0.75f, p_rtVec);
220
221 num = 0;
222 hNode = &cg_particleHeadNode;
223 for (p=hNode->prev ; p!=hNode ; p=next) {
224 next = p->prev;
225 num++;
226
227 if (p->colorVel[3] > PART_INSTANT) {
228 time = (cg.realTime - p->time)*0.001f;
229 color[3] = p->color[3] + time*p->colorVel[3];
230 }
231 else {
232 time = 1;
233 color[3] = p->color[3];
234 }
235
236 // Faded out
237 if (color[3] <= 0.0001f || num > cg_particleMax->intVal) {
238 CG_FreeParticle (p);
239 continue;
240 }
241
242 if (color[3] > 1.0)
243 color[3] = 1.0f;
244
245 // Origin
246 time2 = time*time;
247
248 org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
249 org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
250 org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
251
252 if (p->flags & PF_GRAVITY)
253 org[2] -= (time2 * PART_GRAVITY);
254
255 // Culling
256 switch (p->style) {
257 case PART_STYLE_ANGLED:
258 case PART_STYLE_BEAM:
259 case PART_STYLE_DIRECTION:
260 break;
261
262 default:
263 if (cg_particleCulling->intVal) {
264 // Kill particles behind the view
265 Vec3Subtract (org, cg.refDef.viewOrigin, temp);
266 VectorNormalizeFastf (temp);
267 if (DotProduct (temp, cg.refDef.viewAxis[0]) < 0)
268 goto nextParticle;
269
270 // Lessen fillrate consumption
271 if (!(p->flags & PF_NOCLOSECULL)) {
272 dist = Vec3DistFast (cg.refDef.viewOrigin, org);
273 if (dist <= 5)
274 goto nextParticle;
275 }
276 }
277 break;
278 }
279
280 // sizeVel calcs
281 if (p->colorVel[3] > PART_INSTANT && p->size != p->sizeVel) {
282 if (p->size > p->sizeVel) // shrink
283 size = p->size - ((p->size - p->sizeVel) * (p->color[3] - color[3]));
284 else // grow
285 size = p->size + ((p->sizeVel - p->size) * (p->color[3] - color[3]));
286 }
287 else {
288 size = p->size;
289 }
290
291 if (size < 0.0f)
292 goto nextParticle;
293
294 // colorVel calcs
295 Vec3Copy (p->color, color);
296 if (p->colorVel[3] > PART_INSTANT) {
297 for (i=0 ; i<3 ; i++) {
298 if (p->color[i] != p->colorVel[i]) {
299 if (p->color[i] > p->colorVel[i])
300 color[i] = p->color[i] - ((p->color[i] - p->colorVel[i]) * (p->color[3] - color[3]));
301 else
302 color[i] = p->color[i] + ((p->colorVel[i] - p->color[i]) * (p->color[3] - color[3]));
303 }
304
305 color[i] = clamp (color[i], 0, 255);
306 }
307 }
308
309 // Particle shading
310 if (p->flags & PF_SHADE && cg_particleShading->intVal) {
311 cgi.R_LightPoint (p->org, shade);
312
313 lightest = 0;
314 for (j=0 ; j<3 ; j++) {
315 color[j] = ((0.7f * clamp (shade[j], 0.0f, 1.0f)) + 0.3f) * p->color[j];
316 if (color[j] > lightest)
317 lightest = color[j];
318 }
319
320 if (lightest > 255.0) {
321 color[0] *= 255.0f / lightest;
322 color[1] *= 255.0f / lightest;
323 color[2] *= 255.0f / lightest;
324 }
325 }
326
327 // Alpha*color
328 if (p->flags & PF_ALPHACOLOR)
329 Vec3Scale (color, color[3], color);
330
331 // Think function
332 orient = p->orient;
333 if (p->thinkNext && p->think) {
334 p->thinkNext = qFalse;
335 p->think (p, org, p->angle, color, &size, &orient, &time);
336 }
337
338 if (color[3] <= 0.0f)
339 goto nextParticle;
340
341 // Contents requirements
342 pointBits = 0;
343 if (cg.currGameMod != GAME_MOD_LOX && cg.currGameMod != GAME_MOD_GIEX) { // FIXME: yay hack
344 if (p->flags & PF_AIRONLY) {
345 pointBits |= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
346 if (cgi.CM_PointContents (org, 0) & pointBits) {
347 p->color[3] = 0;
348 p->colorVel[3] = 0;
349 goto nextParticle;
350 }
351 }
352 else {
353 if (p->flags & PF_LAVAONLY) pointBits |= CONTENTS_LAVA;
354 if (p->flags & PF_SLIMEONLY) pointBits |= CONTENTS_SLIME;
355 if (p->flags & PF_WATERONLY) pointBits |= CONTENTS_WATER;
356
357 if (pointBits) {
358 if (!(cgi.CM_PointContents (org, 0) & pointBits)) {
359 p->color[3] = 0;
360 p->colorVel[3] = 0;
361 goto nextParticle;
362 }
363 }
364 }
365 }
366
367 // Add to be rendered
368 if (p->flags & PF_SCALED) {
369 scale = (org[0] - cg.refDef.viewOrigin[0]) * cg.refDef.viewAxis[0][0] +
370 (org[1] - cg.refDef.viewOrigin[1]) * cg.refDef.viewAxis[0][1] +
371 (org[2] - cg.refDef.viewOrigin[2]) * cg.refDef.viewAxis[0][2];
372
373 scale = (scale < 20) ? 1 : 1 + scale * 0.004f;
374 }
375 else
376 scale = 1;
377
378 scale = (scale - 1) + size;
379
380 // Rendering
381 outColor[0] = color[0];
382 outColor[1] = color[1];
383 outColor[2] = color[2];
384 outColor[3] = color[3] * 255;
385
386 switch (p->style) {
387 case PART_STYLE_ANGLED:
388 Angles_Vectors (p->angle, NULL, a_rtVec, a_upVec);
389
390 if (orient) {
391 float c = (float)cos (DEG2RAD (orient)) * scale;
392 float s = (float)sin (DEG2RAD (orient)) * scale;
393
394 // Top left
395 Vec2Set (p->outCoords[0], 0, 0);
396 Vec3Set (p->outVertices[0], org[0] + a_upVec[0]*s - a_rtVec[0]*c,
397 org[1] + a_upVec[1]*s - a_rtVec[1]*c,
398 org[2] + a_upVec[2]*s - a_rtVec[2]*c);
399
400 // Bottom left
401 Vec2Set (p->outCoords[1], 0, 1);
402 Vec3Set (p->outVertices[1], org[0] - a_upVec[0]*c - a_rtVec[0]*s,
403 org[1] - a_upVec[1]*c - a_rtVec[1]*s,
404 org[2] - a_upVec[2]*c - a_rtVec[2]*s);
405
406 // Bottom right
407 Vec2Set (p->outCoords[2], 1, 1);
408 Vec3Set (p->outVertices[2], org[0] - a_upVec[0]*s + a_rtVec[0]*c,
409 org[1] - a_upVec[1]*s + a_rtVec[1]*c,
410 org[2] - a_upVec[2]*s + a_rtVec[2]*c);
411
412 // Top right
413 Vec2Set (p->outCoords[3], 1, 0);
414 Vec3Set (p->outVertices[3], org[0] + a_upVec[0]*c + a_rtVec[0]*s,
415 org[1] + a_upVec[1]*c + a_rtVec[1]*s,
416 org[2] + a_upVec[2]*c + a_rtVec[2]*s);
417 }
418 else {
419 // Top left
420 Vec2Set (p->outCoords[0], 0, 0);
421 Vec3Set (p->outVertices[0], org[0] + a_upVec[0]*scale - a_rtVec[0]*scale,
422 org[1] + a_upVec[1]*scale - a_rtVec[1]*scale,
423 org[2] + a_upVec[2]*scale - a_rtVec[2]*scale);
424
425 // Bottom left
426 Vec2Set (p->outCoords[1], 0, 1);
427 Vec3Set (p->outVertices[1], org[0] - a_upVec[0]*scale - a_rtVec[0]*scale,
428 org[1] - a_upVec[1]*scale - a_rtVec[1]*scale,
429 org[2] - a_upVec[2]*scale - a_rtVec[2]*scale);
430
431 // Bottom right
432 Vec2Set (p->outCoords[2], 1, 1);
433 Vec3Set (p->outVertices[2], org[0] - a_upVec[0]*scale + a_rtVec[0]*scale,
434 org[1] - a_upVec[1]*scale + a_rtVec[1]*scale,
435 org[2] - a_upVec[2]*scale + a_rtVec[2]*scale);
436
437 // Top right
438 Vec2Set (p->outCoords[3], 1, 0);
439 Vec3Set (p->outVertices[3], org[0] + a_upVec[0]*scale + a_rtVec[0]*scale,
440 org[1] + a_upVec[1]*scale + a_rtVec[1]*scale,
441 org[2] + a_upVec[2]*scale + a_rtVec[2]*scale);
442 }
443
444 // Render it
445 *(int *)p->outColor[0] = *(int *)outColor;
446 *(int *)p->outColor[1] = *(int *)outColor;
447 *(int *)p->outColor[2] = *(int *)outColor;
448 *(int *)p->outColor[3] = *(int *)outColor;
449
450 p->outPoly.shader = p->shader;
451 Vec3Copy (p->org, p->outPoly.origin);
452 p->outPoly.radius = scale;
453
454 cgi.R_AddPoly (&p->outPoly);
455 break;
456
457 case PART_STYLE_BEAM:
458 Vec3Subtract (org, cg.refDef.viewOrigin, point);
459 CrossProduct (point, p->angle, width);
460 VectorNormalizeFastf (width);
461 Vec3Scale (width, scale, width);
462
463 Vec3Add (org, p->angle, delta);
464
465 dist = Vec3DistFast (org, delta);
466
467 Vec2Set (p->outCoords[0], 1, dist);
468 Vec3Set (p->outVertices[0], org[0] + width[0],
469 org[1] + width[1],
470 org[2] + width[2]);
471
472 Vec2Set (p->outCoords[1], 0, 0);
473 Vec3Set (p->outVertices[1], org[0] - width[0],
474 org[1] - width[1],
475 org[2] - width[2]);
476
477 Vec3Add (point, p->angle, point);
478 CrossProduct (point, p->angle, width);
479 VectorNormalizeFastf (width);
480 Vec3Scale (width, scale, width);
481
482 Vec2Set (p->outCoords[2], 0, 0);
483 Vec3Set (p->outVertices[2], org[0] + p->angle[0] - width[0],
484 org[1] + p->angle[1] - width[1],
485 org[2] + p->angle[2] - width[2]);
486
487 Vec2Set (p->outCoords[3], 1, dist);
488 Vec3Set (p->outVertices[3], org[0] + p->angle[0] + width[0],
489 org[1] + p->angle[1] + width[1],
490 org[2] + p->angle[2] + width[2]);
491
492 // Render it
493 *(int *)p->outColor[0] = *(int *)outColor;
494 *(int *)p->outColor[1] = *(int *)outColor;
495 *(int *)p->outColor[2] = *(int *)outColor;
496 *(int *)p->outColor[3] = *(int *)outColor;
497
498 p->outPoly.shader = p->shader;
499 Vec3Copy (p->org, p->outPoly.origin);
500 p->outPoly.radius = Vec3DistFast (org, delta);
501
502 cgi.R_AddPoly (&p->outPoly);
503 break;
504
505 case PART_STYLE_DIRECTION:
506 Vec3Add (p->angle, org, vdelta);
507
508 Vec3Subtract (org, vdelta, move);
509 VectorNormalizeFastf (move);
510
511 Vec3Copy (move, a_upVec);
512 Vec3Subtract (cg.refDef.viewOrigin, vdelta, delta);
513 CrossProduct (a_upVec, delta, a_rtVec);
514
515 VectorNormalizeFastf (a_rtVec);
516
517 Vec3Scale (a_rtVec, 0.75f, a_rtVec);
518 Vec3Scale (a_upVec, 0.75f * Vec3LengthFast (p->angle), a_upVec);
519
520 // Top left
521 Vec2Set (p->outCoords[0], 0, 0);
522 Vec3Set (p->outVertices[0], org[0] + a_upVec[0]*scale - a_rtVec[0]*scale,
523 org[1] + a_upVec[1]*scale - a_rtVec[1]*scale,
524 org[2] + a_upVec[2]*scale - a_rtVec[2]*scale);
525
526 // Bottom left
527 Vec2Set (p->outCoords[1], 0, 1);
528 Vec3Set (p->outVertices[1], org[0] - a_upVec[0]*scale - a_rtVec[0]*scale,
529 org[1] - a_upVec[1]*scale - a_rtVec[1]*scale,
530 org[2] - a_upVec[2]*scale - a_rtVec[2]*scale);
531
532 // Bottom right
533 Vec2Set (p->outCoords[2], 1, 1);
534 Vec3Set (p->outVertices[2], org[0] - a_upVec[0]*scale + a_rtVec[0]*scale,
535 org[1] - a_upVec[1]*scale + a_rtVec[1]*scale,
536 org[2] - a_upVec[2]*scale + a_rtVec[2]*scale);
537
538 // Top right
539 Vec2Set (p->outCoords[3], 1, 0);
540 Vec3Set (p->outVertices[3], org[0] + a_upVec[0]*scale + a_rtVec[0]*scale,
541 org[1] + a_upVec[1]*scale + a_rtVec[1]*scale,
542 org[2] + a_upVec[2]*scale + a_rtVec[2]*scale);
543
544 // Render it
545 *(int *)p->outColor[0] = *(int *)outColor;
546 *(int *)p->outColor[1] = *(int *)outColor;
547 *(int *)p->outColor[2] = *(int *)outColor;
548 *(int *)p->outColor[3] = *(int *)outColor;
549
550 p->outPoly.shader = p->shader;
551 Vec3Copy (p->org, p->outPoly.origin);
552 p->outPoly.radius = scale;
553
554 cgi.R_AddPoly (&p->outPoly);
555 break;
556
557 default:
558 case PART_STYLE_QUAD:
559 if (orient) {
560 float c = (float)cos (DEG2RAD (orient)) * scale;
561 float s = (float)sin (DEG2RAD (orient)) * scale;
562
563 // Top left
564 Vec2Set (p->outCoords[0], 0.0, 0.0);
565 Vec3Set (p->outVertices[0], org[0] + cg.refDef.viewAxis[1][0]*c + cg.refDef.viewAxis[2][0]*s,
566 org[1] + cg.refDef.viewAxis[1][1]*c + cg.refDef.viewAxis[2][1]*s,
567 org[2] + cg.refDef.viewAxis[1][2]*c + cg.refDef.viewAxis[2][2]*s);
568
569 // Bottom left
570 Vec2Set (p->outCoords[1], 0.0, 1.0);
571 Vec3Set (p->outVertices[1], org[0] - cg.refDef.viewAxis[1][0]*s + cg.refDef.viewAxis[2][0]*c,
572 org[1] - cg.refDef.viewAxis[1][1]*s + cg.refDef.viewAxis[2][1]*c,
573 org[2] - cg.refDef.viewAxis[1][2]*s + cg.refDef.viewAxis[2][2]*c);
574
575 // Bottom right
576 Vec2Set (p->outCoords[2], 1.0, 1.0);
577 Vec3Set (p->outVertices[2], org[0] - cg.refDef.viewAxis[1][0]*c - cg.refDef.viewAxis[2][0]*s,
578 org[1] - cg.refDef.viewAxis[1][1]*c - cg.refDef.viewAxis[2][1]*s,
579 org[2] - cg.refDef.viewAxis[1][2]*c - cg.refDef.viewAxis[2][2]*s);
580
581 // Top right
582 Vec2Set (p->outCoords[3], 1.0, 0.0);
583 Vec3Set (p->outVertices[3], org[0] + cg.refDef.viewAxis[1][0]*s - cg.refDef.viewAxis[2][0]*c,
584 org[1] + cg.refDef.viewAxis[1][1]*s - cg.refDef.viewAxis[2][1]*c,
585 org[2] + cg.refDef.viewAxis[1][2]*s - cg.refDef.viewAxis[2][2]*c);
586 }
587 else {
588 // Top left
589 Vec2Set (p->outCoords[0], 0, 0);
590 Vec3Set (p->outVertices[0], org[0] + cg.refDef.viewAxis[2][0]*scale + cg.refDef.viewAxis[1][0]*scale,
591 org[1] + cg.refDef.viewAxis[2][1]*scale + cg.refDef.viewAxis[1][1]*scale,
592 org[2] + cg.refDef.viewAxis[2][2]*scale + cg.refDef.viewAxis[1][2]*scale);
593
594 // Bottom left
595 Vec2Set (p->outCoords[1], 0, 1);
596 Vec3Set (p->outVertices[1], org[0] - cg.refDef.viewAxis[2][0]*scale + cg.refDef.viewAxis[1][0]*scale,
597 org[1] - cg.refDef.viewAxis[2][1]*scale + cg.refDef.viewAxis[1][1]*scale,
598 org[2] - cg.refDef.viewAxis[2][2]*scale + cg.refDef.viewAxis[1][2]*scale);
599
600 // Bottom right
601 Vec2Set (p->outCoords[2], 1, 1);
602 Vec3Set (p->outVertices[2], org[0] - cg.refDef.viewAxis[2][0]*scale - cg.refDef.viewAxis[1][0]*scale,
603 org[1] - cg.refDef.viewAxis[2][1]*scale - cg.refDef.viewAxis[1][1]*scale,
604 org[2] - cg.refDef.viewAxis[2][2]*scale - cg.refDef.viewAxis[1][2]*scale);
605
606 // Top right
607 Vec2Set (p->outCoords[3], 1, 0);
608 Vec3Set (p->outVertices[3], org[0] + cg.refDef.viewAxis[2][0]*scale - cg.refDef.viewAxis[1][0]*scale,
609 org[1] + cg.refDef.viewAxis[2][1]*scale - cg.refDef.viewAxis[1][1]*scale,
610 org[2] + cg.refDef.viewAxis[2][2]*scale - cg.refDef.viewAxis[1][2]*scale);
611 }
612
613 // Render it
614 *(int *)p->outColor[0] = *(int *)outColor;
615 *(int *)p->outColor[1] = *(int *)outColor;
616 *(int *)p->outColor[2] = *(int *)outColor;
617 *(int *)p->outColor[3] = *(int *)outColor;
618
619 p->outPoly.shader = p->shader;
620 Vec3Copy (p->org, p->outPoly.origin);
621 p->outPoly.radius = scale;
622
623 cgi.R_AddPoly (&p->outPoly);
624 break;
625 }
626
627 nextParticle:
628 Vec3Copy (org, p->oldOrigin);
629
630 // Kill if instant
631 if (p->colorVel[3] <= PART_INSTANT) {
632 p->color[3] = 0;
633 p->colorVel[3] = 0;
634 }
635 }
636 }
637