cg_marks.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. //
  19. // cg_marks.c -- wall marks
  20. #include "cg_local.h"
  21. /*
  22. ===================================================================
  23. MARK POLYS
  24. ===================================================================
  25. */
  26. markPoly_t cg_activeMarkPolys; // double linked list
  27. markPoly_t *cg_freeMarkPolys; // single linked list
  28. markPoly_t cg_markPolys[MAX_MARK_POLYS];
  29. static int markTotal;
  30. /*
  31. ===================
  32. CG_InitMarkPolys
  33. This is called at startup and for tournement restarts
  34. ===================
  35. */
  36. void CG_InitMarkPolys( void ) {
  37. int i;
  38. memset( cg_markPolys, 0, sizeof(cg_markPolys) );
  39. cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
  40. cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
  41. cg_freeMarkPolys = cg_markPolys;
  42. for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {
  43. cg_markPolys[i].nextMark = &cg_markPolys[i+1];
  44. }
  45. }
  46. /*
  47. ==================
  48. CG_FreeMarkPoly
  49. ==================
  50. */
  51. void CG_FreeMarkPoly( markPoly_t *le ) {
  52. if ( !le->prevMark ) {
  53. CG_Error( "CG_FreeLocalEntity: not active" );
  54. }
  55. // remove from the doubly linked active list
  56. le->prevMark->nextMark = le->nextMark;
  57. le->nextMark->prevMark = le->prevMark;
  58. // the free list is only singly linked
  59. le->nextMark = cg_freeMarkPolys;
  60. cg_freeMarkPolys = le;
  61. }
  62. /*
  63. ===================
  64. CG_AllocMark
  65. Will allways succeed, even if it requires freeing an old active mark
  66. ===================
  67. */
  68. markPoly_t *CG_AllocMark( void ) {
  69. markPoly_t *le;
  70. int time;
  71. if ( !cg_freeMarkPolys ) {
  72. // no free entities, so free the one at the end of the chain
  73. // remove the oldest active entity
  74. time = cg_activeMarkPolys.prevMark->time;
  75. while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {
  76. CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
  77. }
  78. }
  79. le = cg_freeMarkPolys;
  80. cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
  81. memset( le, 0, sizeof( *le ) );
  82. // link into the active list
  83. le->nextMark = cg_activeMarkPolys.nextMark;
  84. le->prevMark = &cg_activeMarkPolys;
  85. cg_activeMarkPolys.nextMark->prevMark = le;
  86. cg_activeMarkPolys.nextMark = le;
  87. return le;
  88. }
  89. /*
  90. =================
  91. CG_ImpactMark
  92. origin should be a point within a unit of the plane
  93. dir should be the plane normal
  94. temporary marks will not be stored or randomly oriented, but immediately
  95. passed to the renderer.
  96. =================
  97. */
  98. #define MAX_MARK_FRAGMENTS 128
  99. #define MAX_MARK_POINTS 384
  100. void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
  101. float orientation, float red, float green, float blue, float alpha,
  102. qboolean alphaFade, float radius, qboolean temporary ) {
  103. vec3_t axis[3];
  104. float texCoordScale;
  105. vec3_t originalPoints[4];
  106. byte colors[4];
  107. int i, j;
  108. int numFragments;
  109. markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
  110. vec3_t markPoints[MAX_MARK_POINTS];
  111. vec3_t projection;
  112. if ( !cg_addMarks.integer ) {
  113. return;
  114. }
  115. if ( radius <= 0 ) {
  116. CG_Error( "CG_ImpactMark called with <= 0 radius" );
  117. }
  118. //if ( markTotal >= MAX_MARK_POLYS ) {
  119. // return;
  120. //}
  121. // create the texture axis
  122. VectorNormalize2( dir, axis[0] );
  123. PerpendicularVector( axis[1], axis[0] );
  124. RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
  125. CrossProduct( axis[0], axis[2], axis[1] );
  126. texCoordScale = 0.5 * 1.0 / radius;
  127. // create the full polygon
  128. for ( i = 0 ; i < 3 ; i++ ) {
  129. originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
  130. originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
  131. originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
  132. originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
  133. }
  134. // get the fragments
  135. VectorScale( dir, -20, projection );
  136. numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
  137. projection, MAX_MARK_POINTS, markPoints[0],
  138. MAX_MARK_FRAGMENTS, markFragments );
  139. colors[0] = red * 255;
  140. colors[1] = green * 255;
  141. colors[2] = blue * 255;
  142. colors[3] = alpha * 255;
  143. for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
  144. polyVert_t *v;
  145. polyVert_t verts[MAX_VERTS_ON_POLY];
  146. markPoly_t *mark;
  147. // we have an upper limit on the complexity of polygons
  148. // that we store persistantly
  149. if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
  150. mf->numPoints = MAX_VERTS_ON_POLY;
  151. }
  152. for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
  153. vec3_t delta;
  154. VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
  155. VectorSubtract( v->xyz, origin, delta );
  156. v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
  157. v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
  158. *(int *)v->modulate = *(int *)colors;
  159. }
  160. // if it is a temporary (shadow) mark, add it immediately and forget about it
  161. if ( temporary ) {
  162. trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
  163. continue;
  164. }
  165. // otherwise save it persistantly
  166. mark = CG_AllocMark();
  167. mark->time = cg.time;
  168. mark->alphaFade = alphaFade;
  169. mark->markShader = markShader;
  170. mark->poly.numVerts = mf->numPoints;
  171. mark->color[0] = red;
  172. mark->color[1] = green;
  173. mark->color[2] = blue;
  174. mark->color[3] = alpha;
  175. memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
  176. markTotal++;
  177. }
  178. }
  179. /*
  180. ===============
  181. CG_AddMarks
  182. ===============
  183. */
  184. #define MARK_TOTAL_TIME 10000
  185. #define MARK_FADE_TIME 1000
  186. void CG_AddMarks( void ) {
  187. int j;
  188. markPoly_t *mp, *next;
  189. int t;
  190. int fade;
  191. if ( !cg_addMarks.integer ) {
  192. return;
  193. }
  194. mp = cg_activeMarkPolys.nextMark;
  195. for ( ; mp != &cg_activeMarkPolys ; mp = next ) {
  196. // grab next now, so if the local entity is freed we
  197. // still have it
  198. next = mp->nextMark;
  199. // see if it is time to completely remove it
  200. if ( cg.time > mp->time + MARK_TOTAL_TIME ) {
  201. CG_FreeMarkPoly( mp );
  202. continue;
  203. }
  204. // fade out the energy bursts
  205. if ( mp->markShader == cgs.media.energyMarkShader ) {
  206. fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 );
  207. if ( fade < 255 ) {
  208. if ( fade < 0 ) {
  209. fade = 0;
  210. }
  211. if ( mp->verts[0].modulate[0] != 0 ) {
  212. for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
  213. mp->verts[j].modulate[0] = mp->color[0] * fade;
  214. mp->verts[j].modulate[1] = mp->color[1] * fade;
  215. mp->verts[j].modulate[2] = mp->color[2] * fade;
  216. }
  217. }
  218. }
  219. }
  220. // fade all marks out with time
  221. t = mp->time + MARK_TOTAL_TIME - cg.time;
  222. if ( t < MARK_FADE_TIME ) {
  223. fade = 255 * t / MARK_FADE_TIME;
  224. if ( mp->alphaFade ) {
  225. for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
  226. mp->verts[j].modulate[3] = fade;
  227. }
  228. } else {
  229. for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
  230. mp->verts[j].modulate[0] = mp->color[0] * fade;
  231. mp->verts[j].modulate[1] = mp->color[1] * fade;
  232. mp->verts[j].modulate[2] = mp->color[2] * fade;
  233. }
  234. }
  235. }
  236. trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
  237. }
  238. }
  239. // cg_particles.c
  240. #define BLOODRED 2
  241. #define EMISIVEFADE 3
  242. #define GREY75 4
  243. typedef struct particle_s
  244. {
  245. struct particle_s *next;
  246. float time;
  247. float endtime;
  248. vec3_t org;
  249. vec3_t vel;
  250. vec3_t accel;
  251. int color;
  252. float colorvel;
  253. float alpha;
  254. float alphavel;
  255. int type;
  256. qhandle_t pshader;
  257. float height;
  258. float width;
  259. float endheight;
  260. float endwidth;
  261. float start;
  262. float end;
  263. float startfade;
  264. qboolean rotate;
  265. int snum;
  266. qboolean link;
  267. // Ridah
  268. int shaderAnim;
  269. int roll;
  270. int accumroll;
  271. } cparticle_t;
  272. typedef enum
  273. {
  274. P_NONE,
  275. P_WEATHER,
  276. P_FLAT,
  277. P_SMOKE,
  278. P_ROTATE,
  279. P_WEATHER_TURBULENT,
  280. P_ANIM, // Ridah
  281. P_BAT,
  282. P_BLEED,
  283. P_FLAT_SCALEUP,
  284. P_FLAT_SCALEUP_FADE,
  285. P_WEATHER_FLURRY,
  286. P_SMOKE_IMPACT,
  287. P_BUBBLE,
  288. P_BUBBLE_TURBULENT,
  289. P_SPRITE
  290. } particle_type_t;
  291. #define MAX_SHADER_ANIMS 32
  292. #define MAX_SHADER_ANIM_FRAMES 64
  293. static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
  294. "explode1",
  295. NULL
  296. };
  297. static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
  298. static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
  299. 23
  300. };
  301. static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
  302. 1.0f
  303. };
  304. static int numShaderAnims;
  305. // done.
  306. #define PARTICLE_GRAVITY 40
  307. #define MAX_PARTICLES 1024
  308. cparticle_t *active_particles, *free_particles;
  309. cparticle_t particles[MAX_PARTICLES];
  310. int cl_numparticles = MAX_PARTICLES;
  311. qboolean initparticles = qfalse;
  312. vec3_t pvforward, pvright, pvup;
  313. vec3_t rforward, rright, rup;
  314. float oldtime;
  315. /*
  316. ===============
  317. CL_ClearParticles
  318. ===============
  319. */
  320. void CG_ClearParticles (void)
  321. {
  322. int i;
  323. memset( particles, 0, sizeof(particles) );
  324. free_particles = &particles[0];
  325. active_particles = NULL;
  326. for (i=0 ;i<cl_numparticles ; i++)
  327. {
  328. particles[i].next = &particles[i+1];
  329. particles[i].type = 0;
  330. }
  331. particles[cl_numparticles-1].next = NULL;
  332. oldtime = cg.time;
  333. // Ridah, init the shaderAnims
  334. for (i=0; shaderAnimNames[i]; i++) {
  335. int j;
  336. for (j=0; j<shaderAnimCounts[i]; j++) {
  337. shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
  338. }
  339. }
  340. numShaderAnims = i;
  341. // done.
  342. initparticles = qtrue;
  343. }
  344. /*
  345. =====================
  346. CG_AddParticleToScene
  347. =====================
  348. */
  349. void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
  350. {
  351. vec3_t point;
  352. polyVert_t verts[4];
  353. float width;
  354. float height;
  355. float time, time2;
  356. float ratio;
  357. float invratio;
  358. vec3_t color;
  359. polyVert_t TRIverts[3];
  360. vec3_t rright2, rup2;
  361. if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
  362. || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
  363. {// create a front facing polygon
  364. if (p->type != P_WEATHER_FLURRY)
  365. {
  366. if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
  367. {
  368. if (org[2] > p->end)
  369. {
  370. p->time = cg.time;
  371. VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
  372. p->org[2] = ( p->start + crandom () * 4 );
  373. if (p->type == P_BUBBLE_TURBULENT)
  374. {
  375. p->vel[0] = crandom() * 4;
  376. p->vel[1] = crandom() * 4;
  377. }
  378. }
  379. }
  380. else
  381. {
  382. if (org[2] < p->end)
  383. {
  384. p->time = cg.time;
  385. VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
  386. while (p->org[2] < p->end)
  387. {
  388. p->org[2] += (p->start - p->end);
  389. }
  390. if (p->type == P_WEATHER_TURBULENT)
  391. {
  392. p->vel[0] = crandom() * 16;
  393. p->vel[1] = crandom() * 16;
  394. }
  395. }
  396. }
  397. // Rafael snow pvs check
  398. if (!p->link)
  399. return;
  400. p->alpha = 1;
  401. }
  402. // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
  403. if (Distance( cg.snap->ps.origin, org ) > 1024) {
  404. return;
  405. }
  406. // done.
  407. if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
  408. {
  409. VectorMA (org, -p->height, pvup, point);
  410. VectorMA (point, -p->width, pvright, point);
  411. VectorCopy (point, verts[0].xyz);
  412. verts[0].st[0] = 0;
  413. verts[0].st[1] = 0;
  414. verts[0].modulate[0] = 255;
  415. verts[0].modulate[1] = 255;
  416. verts[0].modulate[2] = 255;
  417. verts[0].modulate[3] = 255 * p->alpha;
  418. VectorMA (org, -p->height, pvup, point);
  419. VectorMA (point, p->width, pvright, point);
  420. VectorCopy (point, verts[1].xyz);
  421. verts[1].st[0] = 0;
  422. verts[1].st[1] = 1;
  423. verts[1].modulate[0] = 255;
  424. verts[1].modulate[1] = 255;
  425. verts[1].modulate[2] = 255;
  426. verts[1].modulate[3] = 255 * p->alpha;
  427. VectorMA (org, p->height, pvup, point);
  428. VectorMA (point, p->width, pvright, point);
  429. VectorCopy (point, verts[2].xyz);
  430. verts[2].st[0] = 1;
  431. verts[2].st[1] = 1;
  432. verts[2].modulate[0] = 255;
  433. verts[2].modulate[1] = 255;
  434. verts[2].modulate[2] = 255;
  435. verts[2].modulate[3] = 255 * p->alpha;
  436. VectorMA (org, p->height, pvup, point);
  437. VectorMA (point, -p->width, pvright, point);
  438. VectorCopy (point, verts[3].xyz);
  439. verts[3].st[0] = 1;
  440. verts[3].st[1] = 0;
  441. verts[3].modulate[0] = 255;
  442. verts[3].modulate[1] = 255;
  443. verts[3].modulate[2] = 255;
  444. verts[3].modulate[3] = 255 * p->alpha;
  445. }
  446. else
  447. {
  448. VectorMA (org, -p->height, pvup, point);
  449. VectorMA (point, -p->width, pvright, point);
  450. VectorCopy( point, TRIverts[0].xyz );
  451. TRIverts[0].st[0] = 1;
  452. TRIverts[0].st[1] = 0;
  453. TRIverts[0].modulate[0] = 255;
  454. TRIverts[0].modulate[1] = 255;
  455. TRIverts[0].modulate[2] = 255;
  456. TRIverts[0].modulate[3] = 255 * p->alpha;
  457. VectorMA (org, p->height, pvup, point);
  458. VectorMA (point, -p->width, pvright, point);
  459. VectorCopy (point, TRIverts[1].xyz);
  460. TRIverts[1].st[0] = 0;
  461. TRIverts[1].st[1] = 0;
  462. TRIverts[1].modulate[0] = 255;
  463. TRIverts[1].modulate[1] = 255;
  464. TRIverts[1].modulate[2] = 255;
  465. TRIverts[1].modulate[3] = 255 * p->alpha;
  466. VectorMA (org, p->height, pvup, point);
  467. VectorMA (point, p->width, pvright, point);
  468. VectorCopy (point, TRIverts[2].xyz);
  469. TRIverts[2].st[0] = 0;
  470. TRIverts[2].st[1] = 1;
  471. TRIverts[2].modulate[0] = 255;
  472. TRIverts[2].modulate[1] = 255;
  473. TRIverts[2].modulate[2] = 255;
  474. TRIverts[2].modulate[3] = 255 * p->alpha;
  475. }
  476. }
  477. else if (p->type == P_SPRITE)
  478. {
  479. vec3_t rr, ru;
  480. vec3_t rotate_ang;
  481. VectorSet (color, 1.0, 1.0, 0.5);
  482. time = cg.time - p->time;
  483. time2 = p->endtime - p->time;
  484. ratio = time / time2;
  485. width = p->width + ( ratio * ( p->endwidth - p->width) );
  486. height = p->height + ( ratio * ( p->endheight - p->height) );
  487. if (p->roll) {
  488. vectoangles( cg.refdef.viewaxis[0], rotate_ang );
  489. rotate_ang[ROLL] += p->roll;
  490. AngleVectors ( rotate_ang, NULL, rr, ru);
  491. }
  492. if (p->roll) {
  493. VectorMA (org, -height, ru, point);
  494. VectorMA (point, -width, rr, point);
  495. } else {
  496. VectorMA (org, -height, pvup, point);
  497. VectorMA (point, -width, pvright, point);
  498. }
  499. VectorCopy (point, verts[0].xyz);
  500. verts[0].st[0] = 0;
  501. verts[0].st[1] = 0;
  502. verts[0].modulate[0] = 255;
  503. verts[0].modulate[1] = 255;
  504. verts[0].modulate[2] = 255;
  505. verts[0].modulate[3] = 255;
  506. if (p->roll) {
  507. VectorMA (point, 2*height, ru, point);
  508. } else {
  509. VectorMA (point, 2*height, pvup, point);
  510. }
  511. VectorCopy (point, verts[1].xyz);
  512. verts[1].st[0] = 0;
  513. verts[1].st[1] = 1;
  514. verts[1].modulate[0] = 255;
  515. verts[1].modulate[1] = 255;
  516. verts[1].modulate[2] = 255;
  517. verts[1].modulate[3] = 255;
  518. if (p->roll) {
  519. VectorMA (point, 2*width, rr, point);
  520. } else {
  521. VectorMA (point, 2*width, pvright, point);
  522. }
  523. VectorCopy (point, verts[2].xyz);
  524. verts[2].st[0] = 1;
  525. verts[2].st[1] = 1;
  526. verts[2].modulate[0] = 255;
  527. verts[2].modulate[1] = 255;
  528. verts[2].modulate[2] = 255;
  529. verts[2].modulate[3] = 255;
  530. if (p->roll) {
  531. VectorMA (point, -2*height, ru, point);
  532. } else {
  533. VectorMA (point, -2*height, pvup, point);
  534. }
  535. VectorCopy (point, verts[3].xyz);
  536. verts[3].st[0] = 1;
  537. verts[3].st[1] = 0;
  538. verts[3].modulate[0] = 255;
  539. verts[3].modulate[1] = 255;
  540. verts[3].modulate[2] = 255;
  541. verts[3].modulate[3] = 255;
  542. }
  543. else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
  544. {// create a front rotating facing polygon
  545. if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
  546. return;
  547. }
  548. if (p->color == BLOODRED)
  549. VectorSet (color, 0.22f, 0.0f, 0.0f);
  550. else if (p->color == GREY75)
  551. {
  552. float len;
  553. float greyit;
  554. float val;
  555. len = Distance (cg.snap->ps.origin, org);
  556. if (!len)
  557. len = 1;
  558. val = 4096/len;
  559. greyit = 0.25 * val;
  560. if (greyit > 0.5)
  561. greyit = 0.5;
  562. VectorSet (color, greyit, greyit, greyit);
  563. }
  564. else
  565. VectorSet (color, 1.0, 1.0, 1.0);
  566. time = cg.time - p->time;
  567. time2 = p->endtime - p->time;
  568. ratio = time / time2;
  569. if (cg.time > p->startfade)
  570. {
  571. invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
  572. if (p->color == EMISIVEFADE)
  573. {
  574. float fval;
  575. fval = (invratio * invratio);
  576. if (fval < 0)
  577. fval = 0;
  578. VectorSet (color, fval , fval , fval );
  579. }
  580. invratio *= p->alpha;
  581. }
  582. else
  583. invratio = 1 * p->alpha;
  584. if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
  585. invratio = 1;
  586. if (invratio > 1)
  587. invratio = 1;
  588. width = p->width + ( ratio * ( p->endwidth - p->width) );
  589. height = p->height + ( ratio * ( p->endheight - p->height) );
  590. if (p->type != P_SMOKE_IMPACT)
  591. {
  592. vec3_t temp;
  593. vectoangles (rforward, temp);
  594. p->accumroll += p->roll;
  595. temp[ROLL] += p->accumroll * 0.1;
  596. AngleVectors ( temp, NULL, rright2, rup2);
  597. }
  598. else
  599. {
  600. VectorCopy (rright, rright2);
  601. VectorCopy (rup, rup2);
  602. }
  603. if (p->rotate)
  604. {
  605. VectorMA (org, -height, rup2, point);
  606. VectorMA (point, -width, rright2, point);
  607. }
  608. else
  609. {
  610. VectorMA (org, -p->height, pvup, point);
  611. VectorMA (point, -p->width, pvright, point);
  612. }
  613. VectorCopy (point, verts[0].xyz);
  614. verts[0].st[0] = 0;
  615. verts[0].st[1] = 0;
  616. verts[0].modulate[0] = 255 * color[0];
  617. verts[0].modulate[1] = 255 * color[1];
  618. verts[0].modulate[2] = 255 * color[2];
  619. verts[0].modulate[3] = 255 * invratio;
  620. if (p->rotate)
  621. {
  622. VectorMA (org, -height, rup2, point);
  623. VectorMA (point, width, rright2, point);
  624. }
  625. else
  626. {
  627. VectorMA (org, -p->height, pvup, point);
  628. VectorMA (point, p->width, pvright, point);
  629. }
  630. VectorCopy (point, verts[1].xyz);
  631. verts[1].st[0] = 0;
  632. verts[1].st[1] = 1;
  633. verts[1].modulate[0] = 255 * color[0];
  634. verts[1].modulate[1] = 255 * color[1];
  635. verts[1].modulate[2] = 255 * color[2];
  636. verts[1].modulate[3] = 255 * invratio;
  637. if (p->rotate)
  638. {
  639. VectorMA (org, height, rup2, point);
  640. VectorMA (point, width, rright2, point);
  641. }
  642. else
  643. {
  644. VectorMA (org, p->height, pvup, point);
  645. VectorMA (point, p->width, pvright, point);
  646. }
  647. VectorCopy (point, verts[2].xyz);
  648. verts[2].st[0] = 1;
  649. verts[2].st[1] = 1;
  650. verts[2].modulate[0] = 255 * color[0];
  651. verts[2].modulate[1] = 255 * color[1];
  652. verts[2].modulate[2] = 255 * color[2];
  653. verts[2].modulate[3] = 255 * invratio;
  654. if (p->rotate)
  655. {
  656. VectorMA (org, height, rup2, point);
  657. VectorMA (point, -width, rright2, point);
  658. }
  659. else
  660. {
  661. VectorMA (org, p->height, pvup, point);
  662. VectorMA (point, -p->width, pvright, point);
  663. }
  664. VectorCopy (point, verts[3].xyz);
  665. verts[3].st[0] = 1;
  666. verts[3].st[1] = 0;
  667. verts[3].modulate[0] = 255 * color[0];
  668. verts[3].modulate[1] = 255 * color[1];
  669. verts[3].modulate[2] = 255 * color[2];
  670. verts[3].modulate[3] = 255 * invratio;
  671. }
  672. else if (p->type == P_BLEED)
  673. {
  674. vec3_t rr, ru;
  675. vec3_t rotate_ang;
  676. float alpha;
  677. alpha = p->alpha;
  678. if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
  679. alpha = 1;
  680. if (p->roll)
  681. {
  682. vectoangles( cg.refdef.viewaxis[0], rotate_ang );
  683. rotate_ang[ROLL] += p->roll;
  684. AngleVectors ( rotate_ang, NULL, rr, ru);
  685. }
  686. else
  687. {
  688. VectorCopy (pvup, ru);
  689. VectorCopy (pvright, rr);
  690. }
  691. VectorMA (org, -p->height, ru, point);
  692. VectorMA (point, -p->width, rr, point);
  693. VectorCopy (point, verts[0].xyz);
  694. verts[0].st[0] = 0;
  695. verts[0].st[1] = 0;
  696. verts[0].modulate[0] = 111;
  697. verts[0].modulate[1] = 19;
  698. verts[0].modulate[2] = 9;
  699. verts[0].modulate[3] = 255 * alpha;
  700. VectorMA (org, -p->height, ru, point);
  701. VectorMA (point, p->width, rr, point);
  702. VectorCopy (point, verts[1].xyz);
  703. verts[1].st[0] = 0;
  704. verts[1].st[1] = 1;
  705. verts[1].modulate[0] = 111;
  706. verts[1].modulate[1] = 19;
  707. verts[1].modulate[2] = 9;
  708. verts[1].modulate[3] = 255 * alpha;
  709. VectorMA (org, p->height, ru, point);
  710. VectorMA (point, p->width, rr, point);
  711. VectorCopy (point, verts[2].xyz);
  712. verts[2].st[0] = 1;
  713. verts[2].st[1] = 1;
  714. verts[2].modulate[0] = 111;
  715. verts[2].modulate[1] = 19;
  716. verts[2].modulate[2] = 9;
  717. verts[2].modulate[3] = 255 * alpha;
  718. VectorMA (org, p->height, ru, point);
  719. VectorMA (point, -p->width, rr, point);
  720. VectorCopy (point, verts[3].xyz);
  721. verts[3].st[0] = 1;
  722. verts[3].st[1] = 0;
  723. verts[3].modulate[0] = 111;
  724. verts[3].modulate[1] = 19;
  725. verts[3].modulate[2] = 9;
  726. verts[3].modulate[3] = 255 * alpha;
  727. }
  728. else if (p->type == P_FLAT_SCALEUP)
  729. {
  730. float width, height;
  731. float sinR, cosR;
  732. if (p->color == BLOODRED)
  733. VectorSet (color, 1, 1, 1);
  734. else
  735. VectorSet (color, 0.5, 0.5, 0.5);
  736. time = cg.time - p->time;
  737. time2 = p->endtime - p->time;
  738. ratio = time / time2;
  739. width = p->width + ( ratio * ( p->endwidth - p->width) );
  740. height = p->height + ( ratio * ( p->endheight - p->height) );
  741. if (width > p->endwidth)
  742. width = p->endwidth;
  743. if (height > p->endheight)
  744. height = p->endheight;
  745. sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
  746. cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
  747. VectorCopy (org, verts[0].xyz);
  748. verts[0].xyz[0] -= sinR;
  749. verts[0].xyz[1] -= cosR;
  750. verts[0].st[0] = 0;
  751. verts[0].st[1] = 0;
  752. verts[0].modulate[0] = 255 * color[0];
  753. verts[0].modulate[1] = 255 * color[1];
  754. verts[0].modulate[2] = 255 * color[2];
  755. verts[0].modulate[3] = 255;
  756. VectorCopy (org, verts[1].xyz);
  757. verts[1].xyz[0] -= cosR;
  758. verts[1].xyz[1] += sinR;
  759. verts[1].st[0] = 0;
  760. verts[1].st[1] = 1;
  761. verts[1].modulate[0] = 255 * color[0];
  762. verts[1].modulate[1] = 255 * color[1];
  763. verts[1].modulate[2] = 255 * color[2];
  764. verts[1].modulate[3] = 255;
  765. VectorCopy (org, verts[2].xyz);
  766. verts[2].xyz[0] += sinR;
  767. verts[2].xyz[1] += cosR;
  768. verts[2].st[0] = 1;
  769. verts[2].st[1] = 1;
  770. verts[2].modulate[0] = 255 * color[0];
  771. verts[2].modulate[1] = 255 * color[1];
  772. verts[2].modulate[2] = 255 * color[2];
  773. verts[2].modulate[3] = 255;
  774. VectorCopy (org, verts[3].xyz);
  775. verts[3].xyz[0] += cosR;
  776. verts[3].xyz[1] -= sinR;
  777. verts[3].st[0] = 1;
  778. verts[3].st[1] = 0;
  779. verts[3].modulate[0] = 255 * color[0];
  780. verts[3].modulate[1] = 255 * color[1];
  781. verts[3].modulate[2] = 255 * color[2];
  782. verts[3].modulate[3] = 255;
  783. }
  784. else if (p->type == P_FLAT)
  785. {
  786. VectorCopy (org, verts[0].xyz);
  787. verts[0].xyz[0] -= p->height;
  788. verts[0].xyz[1] -= p->width;
  789. verts[0].st[0] = 0;
  790. verts[0].st[1] = 0;
  791. verts[0].modulate[0] = 255;
  792. verts[0].modulate[1] = 255;
  793. verts[0].modulate[2] = 255;
  794. verts[0].modulate[3] = 255;
  795. VectorCopy (org, verts[1].xyz);
  796. verts[1].xyz[0] -= p->height;
  797. verts[1].xyz[1] += p->width;
  798. verts[1].st[0] = 0;
  799. verts[1].st[1] = 1;
  800. verts[1].modulate[0] = 255;
  801. verts[1].modulate[1] = 255;
  802. verts[1].modulate[2] = 255;
  803. verts[1].modulate[3] = 255;
  804. VectorCopy (org, verts[2].xyz);
  805. verts[2].xyz[0] += p->height;
  806. verts[2].xyz[1] += p->width;
  807. verts[2].st[0] = 1;
  808. verts[2].st[1] = 1;
  809. verts[2].modulate[0] = 255;
  810. verts[2].modulate[1] = 255;
  811. verts[2].modulate[2] = 255;
  812. verts[2].modulate[3] = 255;
  813. VectorCopy (org, verts[3].xyz);
  814. verts[3].xyz[0] += p->height;
  815. verts[3].xyz[1] -= p->width;
  816. verts[3].st[0] = 1;
  817. verts[3].st[1] = 0;
  818. verts[3].modulate[0] = 255;
  819. verts[3].modulate[1] = 255;
  820. verts[3].modulate[2] = 255;
  821. verts[3].modulate[3] = 255;
  822. }
  823. // Ridah
  824. else if (p->type == P_ANIM) {
  825. vec3_t rr, ru;
  826. vec3_t rotate_ang;
  827. int i, j;
  828. time = cg.time - p->time;
  829. time2 = p->endtime - p->time;
  830. ratio = time / time2;
  831. if (ratio >= 1.0f) {
  832. ratio = 0.9999f;
  833. }
  834. width = p->width + ( ratio * ( p->endwidth - p->width) );
  835. height = p->height + ( ratio * ( p->endheight - p->height) );
  836. // if we are "inside" this sprite, don't draw
  837. if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
  838. return;
  839. }
  840. i = p->shaderAnim;
  841. j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
  842. p->pshader = shaderAnims[i][j];
  843. if (p->roll) {
  844. vectoangles( cg.refdef.viewaxis[0], rotate_ang );
  845. rotate_ang[ROLL] += p->roll;
  846. AngleVectors ( rotate_ang, NULL, rr, ru);
  847. }
  848. if (p->roll) {
  849. VectorMA (org, -height, ru, point);
  850. VectorMA (point, -width, rr, point);
  851. } else {
  852. VectorMA (org, -height, pvup, point);
  853. VectorMA (point, -width, pvright, point);
  854. }
  855. VectorCopy (point, verts[0].xyz);
  856. verts[0].st[0] = 0;
  857. verts[0].st[1] = 0;
  858. verts[0].modulate[0] = 255;
  859. verts[0].modulate[1] = 255;
  860. verts[0].modulate[2] = 255;
  861. verts[0].modulate[3] = 255;
  862. if (p->roll) {
  863. VectorMA (point, 2*height, ru, point);
  864. } else {
  865. VectorMA (point, 2*height, pvup, point);
  866. }
  867. VectorCopy (point, verts[1].xyz);
  868. verts[1].st[0] = 0;
  869. verts[1].st[1] = 1;
  870. verts[1].modulate[0] = 255;
  871. verts[1].modulate[1] = 255;
  872. verts[1].modulate[2] = 255;
  873. verts[1].modulate[3] = 255;
  874. if (p->roll) {
  875. VectorMA (point, 2*width, rr, point);
  876. } else {
  877. VectorMA (point, 2*width, pvright, point);
  878. }
  879. VectorCopy (point, verts[2].xyz);
  880. verts[2].st[0] = 1;
  881. verts[2].st[1] = 1;
  882. verts[2].modulate[0] = 255;
  883. verts[2].modulate[1] = 255;
  884. verts[2].modulate[2] = 255;
  885. verts[2].modulate[3] = 255;
  886. if (p->roll) {
  887. VectorMA (point, -2*height, ru, point);
  888. } else {
  889. VectorMA (point, -2*height, pvup, point);
  890. }
  891. VectorCopy (point, verts[3].xyz);
  892. verts[3].st[0] = 1;
  893. verts[3].st[1] = 0;
  894. verts[3].modulate[0] = 255;
  895. verts[3].modulate[1] = 255;
  896. verts[3].modulate[2] = 255;
  897. verts[3].modulate[3] = 255;
  898. }
  899. // done.
  900. if (!p->pshader) {
  901. // (SA) temp commented out for DM
  902. // CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
  903. return;
  904. }
  905. if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
  906. trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
  907. else
  908. trap_R_AddPolyToScene( p->pshader, 4, verts );
  909. }
  910. // Ridah, made this static so it doesn't interfere with other files
  911. static float roll = 0.0;
  912. /*
  913. ===============
  914. CG_AddParticles
  915. ===============
  916. */
  917. void CG_AddParticles (void)
  918. {
  919. cparticle_t *p, *next;
  920. float alpha;
  921. float time, time2;
  922. vec3_t org;
  923. int color;
  924. cparticle_t *active, *tail;
  925. int type;
  926. vec3_t rotate_ang;
  927. if (!initparticles)
  928. CG_ClearParticles ();
  929. VectorCopy( cg.refdef.viewaxis[0], pvforward );
  930. VectorCopy( cg.refdef.viewaxis[1], pvright );
  931. VectorCopy( cg.refdef.viewaxis[2], pvup );
  932. vectoangles( cg.refdef.viewaxis[0], rotate_ang );
  933. roll += ((cg.time - oldtime) * 0.1) ;
  934. rotate_ang[ROLL] += (roll*0.9);
  935. AngleVectors ( rotate_ang, rforward, rright, rup);
  936. oldtime = cg.time;
  937. active = NULL;
  938. tail = NULL;
  939. for (p=active_particles ; p ; p=next)
  940. {
  941. next = p->next;
  942. time = (cg.time - p->time)*0.001;
  943. alpha = p->alpha + time*p->alphavel;
  944. if (alpha <= 0)
  945. { // faded out
  946. p->next = free_particles;
  947. free_particles = p;
  948. p->type = 0;
  949. p->color = 0;
  950. p->alpha = 0;
  951. continue;
  952. }
  953. if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
  954. {
  955. if (cg.time > p->endtime)
  956. {
  957. p->next = free_particles;
  958. free_particles = p;
  959. p->type = 0;
  960. p->color = 0;
  961. p->alpha = 0;
  962. continue;
  963. }
  964. }
  965. if (p->type == P_WEATHER_FLURRY)
  966. {
  967. if (cg.time > p->endtime)
  968. {
  969. p->next = free_particles;
  970. free_particles = p;
  971. p->type = 0;
  972. p->color = 0;
  973. p->alpha = 0;
  974. continue;
  975. }
  976. }
  977. if (p->type == P_FLAT_SCALEUP_FADE)
  978. {
  979. if (cg.time > p->endtime)
  980. {
  981. p->next = free_particles;
  982. free_particles = p;
  983. p->type = 0;
  984. p->color = 0;
  985. p->alpha = 0;
  986. continue;
  987. }
  988. }
  989. if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
  990. // temporary sprite
  991. CG_AddParticleToScene (p, p->org, alpha);
  992. p->next = free_particles;
  993. free_particles = p;
  994. p->type = 0;
  995. p->color = 0;
  996. p->alpha = 0;
  997. continue;
  998. }
  999. p->next = NULL;
  1000. if (!tail)
  1001. active = tail = p;
  1002. else
  1003. {
  1004. tail->next = p;
  1005. tail = p;
  1006. }
  1007. if (alpha > 1.0)
  1008. alpha = 1;
  1009. color = p->color;
  1010. time2 = time*time;
  1011. org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
  1012. org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
  1013. org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
  1014. type = p->type;
  1015. CG_AddParticleToScene (p, org, alpha);
  1016. }
  1017. active_particles = active;
  1018. }
  1019. /*
  1020. ======================
  1021. CG_AddParticles
  1022. ======================
  1023. */
  1024. void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
  1025. {
  1026. cparticle_t *p;
  1027. qboolean turb = qtrue;
  1028. if (!pshader)
  1029. CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
  1030. if (!free_particles)
  1031. return;
  1032. p = free_particles;
  1033. free_particles = p->next;
  1034. p->next = active_particles;
  1035. active_particles = p;
  1036. p->time = cg.time;
  1037. p->color = 0;
  1038. p->alpha = 0.90f;
  1039. p->alphavel = 0;
  1040. p->start = cent->currentState.origin2[0];
  1041. p->end = cent->currentState.origin2[1];
  1042. p->endtime = cg.time + cent->currentState.time;
  1043. p->startfade = cg.time + cent->currentState.time2;
  1044. p->pshader = pshader;
  1045. if (rand()%100 > 90)
  1046. {
  1047. p->height = 32;
  1048. p->width = 32;
  1049. p->alpha = 0.10f;
  1050. }
  1051. else
  1052. {
  1053. p->height = 1;
  1054. p->width = 1;
  1055. }
  1056. p->vel[2] = -20;
  1057. p->type = P_WEATHER_FLURRY;
  1058. if (turb)
  1059. p->vel[2] = -10;
  1060. VectorCopy(cent->currentState.origin, p->org);
  1061. p->org[0] = p->org[0];
  1062. p->org[1] = p->org[1];
  1063. p->org[2] = p->org[2];
  1064. p->vel[0] = p->vel[1] = 0;
  1065. p->accel[0] = p->accel[1] = p->accel[2] = 0;
  1066. p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
  1067. p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
  1068. p->vel[2] += cent->currentState.angles[2];
  1069. if (turb)
  1070. {
  1071. p->accel[0] = crandom () * 16;
  1072. p->accel[1] = crandom () * 16;
  1073. }
  1074. }
  1075. void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
  1076. {
  1077. cparticle_t *p;
  1078. if (!pshader)
  1079. CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
  1080. if (!free_particles)
  1081. return;
  1082. p = free_particles;
  1083. free_particles = p->next;
  1084. p->next = active_particles;
  1085. active_particles = p;
  1086. p->time = cg.time;
  1087. p->color = 0;
  1088. p->alpha = 0.40f;
  1089. p->alphavel = 0;
  1090. p->start = origin[2];
  1091. p->end = origin2[2];
  1092. p->pshader = pshader;
  1093. p->height = 1;
  1094. p->width = 1;
  1095. p->vel[2] = -50;
  1096. if (turb)
  1097. {
  1098. p->type = P_WEATHER_TURBULENT;
  1099. p->vel[2] = -50 * 1.3;
  1100. }
  1101. else
  1102. {
  1103. p->type = P_WEATHER;
  1104. }
  1105. VectorCopy(origin, p->org);
  1106. p->org[0] = p->org[0] + ( crandom() * range);
  1107. p->org[1] = p->org[1] + ( crandom() * range);
  1108. p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
  1109. p->vel[0] = p->vel[1] = 0;
  1110. p->accel[0] = p->accel[1] = p->accel[2] = 0;
  1111. if (turb)
  1112. {
  1113. p->vel[0] = crandom() * 16;
  1114. p->vel[1] = crandom() * 16;
  1115. }
  1116. // Rafael snow pvs check
  1117. p->snum = snum;
  1118. p->link = qtrue;
  1119. }
  1120. void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
  1121. {
  1122. cparticle_t *p;
  1123. float randsize;
  1124. if (!pshader)
  1125. CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
  1126. if (!free_particles)
  1127. return;
  1128. p = free_particles;
  1129. free_particles = p->next;
  1130. p->next = active_particles;
  1131. active_particles = p;
  1132. p->time = cg.time;
  1133. p->color = 0;
  1134. p->alpha = 0.40f;
  1135. p->alphavel = 0;
  1136. p->start = origin[2];
  1137. p->end = origin2[2];
  1138. p->pshader = pshader;
  1139. randsize = 1 + (crandom() * 0.5);
  1140. p->height = randsize;
  1141. p->width = randsize;
  1142. p->vel[2] = 50 + ( crandom() * 10 );
  1143. if (turb)
  1144. {
  1145. p->type = P_BUBBLE_TURBULENT;
  1146. p->vel[2] = 50 * 1.3;
  1147. }
  1148. else
  1149. {
  1150. p->type = P_BUBBLE;
  1151. }
  1152. VectorCopy(origin, p->org);
  1153. p->org[0] = p->org[0] + ( crandom() * range);
  1154. p->org[1] = p->org[1] + ( crandom() * range);
  1155. p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
  1156. p->vel[0] = p->vel[1] = 0;
  1157. p->accel[0] = p->accel[1] = p->accel[2] = 0;
  1158. if (turb)
  1159. {
  1160. p->vel[0] = crandom() * 4;
  1161. p->vel[1] = crandom() * 4;
  1162. }
  1163. // Rafael snow pvs check
  1164. p->snum = snum;
  1165. p->link = qtrue;
  1166. }
  1167. void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
  1168. {
  1169. // using cent->density = enttime
  1170. // cent->frame = startfade
  1171. cparticle_t *p;
  1172. if (!pshader)
  1173. CG_Printf ("CG_ParticleSmoke == ZERO!\n");
  1174. if (!free_particles)
  1175. return;
  1176. p = free_particles;
  1177. free_particles = p->next;
  1178. p->next = active_particles;
  1179. active_particles = p;
  1180. p->time = cg.time;
  1181. p->endtime = cg.time + cent->currentState.time;
  1182. p->startfade = cg.time + cent->currentState.time2;
  1183. p->color = 0;
  1184. p->alpha = 1.0;
  1185. p->alphavel = 0;
  1186. p->start = cent->currentState.origin[2];
  1187. p->end = cent->currentState.origin2[2];
  1188. p->pshader = pshader;
  1189. p->rotate = qfalse;
  1190. p->height = 8;
  1191. p->width = 8;
  1192. p->endheight = 32;
  1193. p->endwidth = 32;
  1194. p->type = P_SMOKE;
  1195. VectorCopy(cent->currentState.origin, p->org);
  1196. p->vel[0] = p->vel[1] = 0;
  1197. p->accel[0] = p->accel[1] = p->accel[2] = 0;
  1198. p->vel[2] = 5;
  1199. if (cent->currentState.frame == 1)// reverse gravity
  1200. p->vel[2] *= -1;
  1201. p->roll = 8 + (crandom() * 4);
  1202. }
  1203. void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
  1204. {
  1205. cparticle_t *p;
  1206. if (!free_particles)
  1207. return;
  1208. p = free_particles;
  1209. free_particles = p->next;
  1210. p->next = active_particles;
  1211. active_particles = p;
  1212. p->time = cg.time;
  1213. p->endtime = cg.time + duration;
  1214. p->startfade = cg.time + duration/2;
  1215. p->color = EMISIVEFADE;
  1216. p->alpha = 1.0;
  1217. p->alphavel = 0;
  1218. p->height = 0.5;
  1219. p->width = 0.5;
  1220. p->endheight = 0.5;
  1221. p->endwidth = 0.5;
  1222. p->pshader = cgs.media.tracerShader;
  1223. p->type = P_SMOKE;
  1224. VectorCopy(org, p->org);
  1225. p->vel[0] = vel[0];
  1226. p->vel[1] = vel[1];
  1227. p->vel[2] = vel[2];
  1228. p->accel[0] = p->accel[1] = p->accel[2] = 0;
  1229. p->accel[2] = -60;
  1230. p->vel[2] += -20;
  1231. }
  1232. /*
  1233. ======================
  1234. CG_ParticleExplosion
  1235. ======================
  1236. */
  1237. void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
  1238. {
  1239. cparticle_t *p;
  1240. int anim;
  1241. if (animStr < (char *)10)
  1242. CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
  1243. // find the animation string
  1244. for (anim=0; shaderAnimNames[anim]; anim++) {
  1245. if (!Q_stricmp( animStr, shaderAnimNames[anim] ))
  1246. break;
  1247. }
  1248. if (!shaderAnimNames[anim]) {
  1249. CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
  1250. return;
  1251. }
  1252. if (!free_particles)
  1253. return;
  1254. p = free_particles;
  1255. free_particles = p->next;
  1256. p->next = active_particles;
  1257. active_particles = p;
  1258. p->time = cg.time;
  1259. p->alpha = 0.5;
  1260. p->alphavel = 0;
  1261. if (duration < 0) {
  1262. duration *= -1;
  1263. p->roll = 0;
  1264. } else {
  1265. p->roll = crandom()*179;
  1266. }
  1267. p->shaderAnim = anim;
  1268. p->width = sizeStart;
  1269. p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
  1270. p->endheight = sizeEnd;
  1271. p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
  1272. p->endtime = cg.time + duration;
  1273. p->type = P_ANIM;
  1274. VectorCopy( origin, p->org );
  1275. VectorCopy( vel, p->vel );
  1276. VectorClear( p->accel );
  1277. }
  1278. // Rafael Shrapnel
  1279. void CG_AddParticleShrapnel (localEntity_t *le)
  1280. {
  1281. return;
  1282. }
  1283. // done.
  1284. int CG_NewParticleArea (int num)
  1285. {
  1286. // const char *str;
  1287. char *str;
  1288. char *token;
  1289. int type;
  1290. vec3_t origin, origin2;
  1291. int i;
  1292. float range = 0;
  1293. int turb;
  1294. int numparticles;
  1295. int snum;
  1296. str = (char *) CG_ConfigString (num);
  1297. if (!str[0])
  1298. return (0);
  1299. // returns type 128 64 or 32
  1300. token = COM_Parse (&str);
  1301. type = atoi (token);
  1302. if (type == 1)
  1303. range = 128;
  1304. else if (type == 2)
  1305. range = 64;
  1306. else if (type == 3)
  1307. range = 32;
  1308. else if (type == 0)
  1309. range = 256;
  1310. else if (type == 4)
  1311. range = 8;
  1312. else if (type == 5)
  1313. range = 16;
  1314. else if (type == 6)
  1315. range = 32;
  1316. else if (type == 7)
  1317. range = 64;
  1318. for (i=0; i<3; i++)
  1319. {
  1320. token = COM_Parse (&str);
  1321. origin[i] = atof (token);
  1322. }
  1323. for (i=0; i<3; i++)
  1324. {
  1325. token = COM_Parse (&str);
  1326. origin2[i] = atof (token);
  1327. }
  1328. token = COM_Parse (&str);
  1329. numparticles = atoi (token);
  1330. token = COM_Parse (&str);
  1331. turb = atoi (token);
  1332. token = COM_Parse (&str);
  1333. snum = atoi (token);
  1334. for (i=0; i<numparticles; i++)
  1335. {
  1336. if (type >= 4)
  1337. CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
  1338. else
  1339. CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
  1340. }
  1341. return (1);
  1342. }
  1343. void CG_SnowLink (centity_t *cent, qboolean particleOn)
  1344. {
  1345. cparticle_t *p, *next;
  1346. int id;
  1347. id = cent->currentState.frame;
  1348. for (p=active_particles ; p ; p=next)
  1349. {
  1350. next = p->next;
  1351. if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
  1352. {
  1353. if (p->snum == id)
  1354. {
  1355. if (particleOn)
  1356. p->link = qtrue;
  1357. else
  1358. p->link = qfalse;
  1359. }
  1360. }
  1361. }
  1362. }
  1363. void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
  1364. {
  1365. cparticle_t *p;
  1366. if (!pshader)
  1367. CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
  1368. if (!free_particles)
  1369. return;
  1370. p = free_particles;
  1371. free_particles = p->next;
  1372. p->next = active_particles;
  1373. active_particles = p;
  1374. p->time = cg.time;
  1375. p->alpha = 0.25;
  1376. p->alphavel = 0;
  1377. p->roll = crandom()*179;
  1378. p->pshader = pshader;
  1379. p->endtime = cg.time + 1000;
  1380. p->startfade = cg.time + 100;
  1381. p->width = rand()%4 + 8;
  1382. p->height = rand()%4 + 8;
  1383. p->endheight = p->height *2;
  1384. p->endwidth = p->width * 2;
  1385. p->endtime = cg.time + 500;
  1386. p->type = P_SMOKE_IMPACT;
  1387. VectorCopy( origin, p->org );
  1388. VectorSet(p->vel, 0, 0, 20);
  1389. VectorSet(p->accel, 0, 0, 20);
  1390. p->rotate = qtrue;
  1391. }
  1392. void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
  1393. {
  1394. cparticle_t *p;
  1395. if (!pshader)
  1396. CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
  1397. if (!free_particles)
  1398. return;
  1399. p = free_particles;
  1400. free_particles = p->next;
  1401. p->next = active_particles;
  1402. active_particles = p;
  1403. p->time = cg.time;
  1404. p->alpha = 1.0;
  1405. p->alphavel = 0;
  1406. p->roll = 0;
  1407. p->pshader = pshader;
  1408. p->endtime = cg.time + duration;
  1409. if (fleshEntityNum)
  1410. p->startfade = cg.time;
  1411. else
  1412. p->startfade = cg.time + 100;
  1413. p->width = 4;
  1414. p->height = 4;
  1415. p->endheight = 4+rand()%3;
  1416. p->endwidth = p->endheight;
  1417. p->type = P_SMOKE;
  1418. VectorCopy( start, p->org );
  1419. p->vel[0] = 0;
  1420. p->vel[1] = 0;
  1421. p->vel[2] = -20;
  1422. VectorClear( p->accel );
  1423. p->rotate = qfalse;
  1424. p->roll = rand()%179;
  1425. p->color = BLOODRED;
  1426. p->alpha = 0.75;
  1427. }
  1428. void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
  1429. {
  1430. cparticle_t *p;
  1431. int time;
  1432. int time2;
  1433. float ratio;
  1434. float duration = 1500;
  1435. time = cg.time;
  1436. time2 = cg.time + cent->currentState.time;
  1437. ratio =(float)1 - ((float)time / (float)time2);
  1438. if (!pshader)
  1439. CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
  1440. if (!free_particles)
  1441. return;
  1442. p = free_particles;
  1443. free_particles = p->next;
  1444. p->next = active_particles;
  1445. active_particles = p;
  1446. p->time = cg.time;
  1447. p->alpha = 1.0;
  1448. p->alphavel = 0;
  1449. p->roll = 0;
  1450. p->pshader = pshader;
  1451. p->endtime = cg.time + duration;
  1452. p->startfade = p->endtime;
  1453. p->width = 1;
  1454. p->height = 3;
  1455. p->endheight = 3;
  1456. p->endwidth = 1;
  1457. p->type = P_SMOKE;
  1458. VectorCopy(cent->currentState.origin, p->org );
  1459. p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
  1460. p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
  1461. p->vel[2] = (cent->currentState.origin2[2]);
  1462. p->snum = 1.0f;
  1463. VectorClear( p->accel );
  1464. p->accel[2] = -20;
  1465. p->rotate = qfalse;
  1466. p->roll = rand()%179;
  1467. p->alpha = 0.75;
  1468. }
  1469. void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
  1470. {
  1471. cparticle_t *p;
  1472. if (!pshader)
  1473. CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
  1474. if (!free_particles)
  1475. return;
  1476. p = free_particles;
  1477. free_particles = p->next;
  1478. p->next = active_particles;
  1479. active_particles = p;
  1480. p->time = cg.time;
  1481. if (cent->currentState.angles2[2])
  1482. p->endtime = cg.time + cent->currentState.angles2[2];
  1483. else
  1484. p->endtime = cg.time + 60000;
  1485. p->startfade = p->endtime;
  1486. p->alpha = 1.0;
  1487. p->alphavel = 0;
  1488. p->roll = 0;
  1489. p->pshader = pshader;
  1490. if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
  1491. {
  1492. p->width = cent->currentState.angles2[0];
  1493. p->height = cent->currentState.angles2[0];
  1494. p->endheight = cent->currentState.angles2[1];
  1495. p->endwidth = cent->currentState.angles2[1];
  1496. }
  1497. else
  1498. {
  1499. p->width = 8;
  1500. p->height = 8;
  1501. p->endheight = 16;
  1502. p->endwidth = 16;
  1503. }
  1504. p->type = P_FLAT_SCALEUP;
  1505. p->snum = 1.0;
  1506. VectorCopy(cent->currentState.origin, p->org );
  1507. p->org[2]+= 0.55 + (crandom() * 0.5);
  1508. p->vel[0] = 0;
  1509. p->vel[1] = 0;
  1510. p->vel[2] = 0;
  1511. VectorClear( p->accel );
  1512. p->rotate = qfalse;
  1513. p->roll = rand()%179;
  1514. p->alpha = 0.75;
  1515. }
  1516. void CG_OilSlickRemove (centity_t *cent)
  1517. {
  1518. cparticle_t *p, *next;
  1519. int id;
  1520. id = 1.0f;
  1521. if (!id)
  1522. CG_Printf ("CG_OilSlickRevove NULL id\n");
  1523. for (p=active_particles ; p ; p=next)
  1524. {
  1525. next = p->next;
  1526. if (p->type == P_FLAT_SCALEUP)
  1527. {
  1528. if (p->snum == id)
  1529. {
  1530. p->endtime = cg.time + 100;
  1531. p->startfade = p->endtime;
  1532. p->type = P_FLAT_SCALEUP_FADE;
  1533. }
  1534. }
  1535. }
  1536. }
  1537. qboolean ValidBloodPool (vec3_t start)
  1538. {
  1539. #define EXTRUDE_DIST 0.5
  1540. vec3_t angles;
  1541. vec3_t right, up;
  1542. vec3_t this_pos, x_pos, center_pos, end_pos;
  1543. float x, y;
  1544. float fwidth, fheight;
  1545. trace_t trace;
  1546. vec3_t normal;
  1547. fwidth = 16;
  1548. fheight = 16;
  1549. VectorSet (normal, 0, 0, 1);
  1550. vectoangles (normal, angles);
  1551. AngleVectors (angles, NULL, right, up);
  1552. VectorMA (start, EXTRUDE_DIST, normal, center_pos);
  1553. for (x= -fwidth/2; x<fwidth; x+= fwidth)
  1554. {
  1555. VectorMA (center_pos, x, right, x_pos);
  1556. for (y= -fheight/2; y<fheight; y+= fheight)
  1557. {
  1558. VectorMA (x_pos, y, up, this_pos);
  1559. VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
  1560. CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
  1561. if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
  1562. return qfalse;
  1563. if (!(!trace.startsolid && trace.fraction < 1))
  1564. return qfalse;
  1565. }
  1566. }
  1567. return qtrue;
  1568. }
  1569. void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
  1570. {
  1571. cparticle_t *p;
  1572. qboolean legit;
  1573. vec3_t start;
  1574. float rndSize;
  1575. if (!pshader)
  1576. CG_Printf ("CG_BloodPool pshader == ZERO!\n");
  1577. if (!free_particles)
  1578. return;
  1579. VectorCopy (tr->endpos, start);
  1580. legit = ValidBloodPool (start);
  1581. if (!legit)
  1582. return;
  1583. p = free_particles;
  1584. free_particles = p->next;
  1585. p->next = active_particles;
  1586. active_particles = p;
  1587. p->time = cg.time;
  1588. p->endtime = cg.time + 3000;
  1589. p->startfade = p->endtime;
  1590. p->alpha = 1.0;
  1591. p->alphavel = 0;
  1592. p->roll = 0;
  1593. p->pshader = pshader;
  1594. rndSize = 0.4 + random()*0.6;
  1595. p->width = 8*rndSize;
  1596. p->height = 8*rndSize;
  1597. p->endheight = 16*rndSize;
  1598. p->endwidth = 16*rndSize;
  1599. p->type = P_FLAT_SCALEUP;
  1600. VectorCopy(start, p->org );
  1601. p->vel[0] = 0;
  1602. p->vel[1] = 0;
  1603. p->vel[2] = 0;
  1604. VectorClear( p->accel );
  1605. p->rotate = qfalse;
  1606. p->roll = rand()%179;
  1607. p->alpha = 0.75;
  1608. p->color = BLOODRED;
  1609. }
  1610. #define NORMALSIZE 16
  1611. #define LARGESIZE 32
  1612. void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
  1613. {
  1614. float length;
  1615. float dist;
  1616. float crittersize;
  1617. vec3_t angles, forward;
  1618. vec3_t point;
  1619. cparticle_t *p;
  1620. int i;
  1621. dist = 0;
  1622. length = VectorLength (dir);
  1623. vectoangles (dir, angles);
  1624. AngleVectors (angles, forward, NULL, NULL);
  1625. crittersize = LARGESIZE;
  1626. if (length)
  1627. dist = length / crittersize;
  1628. if (dist < 1)
  1629. dist = 1;
  1630. VectorCopy (origin, point);
  1631. for (i=0; i<dist; i++)
  1632. {
  1633. VectorMA (point, crittersize, forward, point);
  1634. if (!free_particles)
  1635. return;
  1636. p = free_particles;
  1637. free_particles = p->next;
  1638. p->next = active_particles;
  1639. active_particles = p;
  1640. p->time = cg.time;
  1641. p->alpha = 1.0;
  1642. p->alphavel = 0;
  1643. p->roll = 0;
  1644. p->pshader = cgs.media.smokePuffShader;
  1645. p->endtime = cg.time + 350 + (crandom() * 100);
  1646. p->startfade = cg.time;
  1647. p->width = LARGESIZE;
  1648. p->height = LARGESIZE;
  1649. p->endheight = LARGESIZE;
  1650. p->endwidth = LARGESIZE;
  1651. p->type = P_SMOKE;
  1652. VectorCopy( origin, p->org );
  1653. p->vel[0] = 0;
  1654. p->vel[1] = 0;
  1655. p->vel[2] = -1;
  1656. VectorClear( p->accel );
  1657. p->rotate = qfalse;
  1658. p->roll = rand()%179;
  1659. p->color = BLOODRED;
  1660. p->alpha = 0.75;
  1661. }
  1662. }
  1663. void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
  1664. {
  1665. cparticle_t *p;
  1666. if (!free_particles)
  1667. return;
  1668. p = free_particles;
  1669. free_particles = p->next;
  1670. p->next = active_particles;
  1671. active_particles = p;
  1672. p->time = cg.time;
  1673. p->endtime = cg.time + duration;
  1674. p->startfade = cg.time + duration/2;
  1675. p->color = EMISIVEFADE;
  1676. p->alpha = 0.4f;
  1677. p->alphavel = 0;
  1678. p->height = 0.5;
  1679. p->width = 0.5;
  1680. p->endheight = 0.5;
  1681. p->endwidth = 0.5;
  1682. p->pshader = cgs.media.tracerShader;
  1683. p->type = P_SMOKE;
  1684. VectorCopy(org, p->org);
  1685. p->org[0] += (crandom() * x);
  1686. p->org[1] += (crandom() * y);
  1687. p->vel[0] = vel[0];
  1688. p->vel[1] = vel[1];
  1689. p->vel[2] = vel[2];
  1690. p->accel[0] = p->accel[1] = p->accel[2] = 0;
  1691. p->vel[0] += (crandom() * 4);
  1692. p->vel[1] += (crandom() * 4);
  1693. p->vel[2] += (20 + (crandom() * 10)) * speed;
  1694. p->accel[0] = crandom () * 4;
  1695. p->accel[1] = crandom () * 4;
  1696. }
  1697. void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
  1698. {
  1699. float length;
  1700. float dist;
  1701. float crittersize;
  1702. vec3_t angles, forward;
  1703. vec3_t point;
  1704. cparticle_t *p;
  1705. int i;
  1706. dist = 0;
  1707. VectorNegate (dir, dir);
  1708. length = VectorLength (dir);
  1709. vectoangles (dir, angles);
  1710. AngleVectors (angles, forward, NULL, NULL);
  1711. crittersize = LARGESIZE;
  1712. if (length)
  1713. dist = length / crittersize;
  1714. if (dist < 1)
  1715. dist = 1;
  1716. VectorCopy (origin, point);
  1717. for (i=0; i<dist; i++)
  1718. {
  1719. VectorMA (point, crittersize, forward, point);
  1720. if (!free_particles)
  1721. return;
  1722. p = free_particles;
  1723. free_particles = p->next;
  1724. p->next = active_particles;
  1725. active_particles = p;
  1726. p->time = cg.time;
  1727. p->alpha = 5.0;
  1728. p->alphavel = 0;
  1729. p->roll = 0;
  1730. p->pshader = cgs.media.smokePuffShader;
  1731. // RF, stay around for long enough to expand and dissipate naturally
  1732. if (length)
  1733. p->endtime = cg.time + 4500 + (crandom() * 3500);
  1734. else
  1735. p->endtime = cg.time + 750 + (crandom() * 500);
  1736. p->startfade = cg.time;
  1737. p->width = LARGESIZE;
  1738. p->height = LARGESIZE;
  1739. // RF, expand while falling
  1740. p->endheight = LARGESIZE*3.0;
  1741. p->endwidth = LARGESIZE*3.0;
  1742. if (!length)
  1743. {
  1744. p->width *= 0.2f;
  1745. p->height *= 0.2f;
  1746. p->endheight = NORMALSIZE;
  1747. p->endwidth = NORMALSIZE;
  1748. }
  1749. p->type = P_SMOKE;
  1750. VectorCopy( point, p->org );
  1751. p->vel[0] = crandom()*6;
  1752. p->vel[1] = crandom()*6;
  1753. p->vel[2] = random()*20;
  1754. // RF, add some gravity/randomness
  1755. p->accel[0] = crandom()*3;
  1756. p->accel[1] = crandom()*3;
  1757. p->accel[2] = -PARTICLE_GRAVITY*0.4;
  1758. VectorClear( p->accel );
  1759. p->rotate = qfalse;
  1760. p->roll = rand()%179;
  1761. p->alpha = 0.75;
  1762. }
  1763. }
  1764. void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
  1765. {
  1766. cparticle_t *p;
  1767. if (!pshader)
  1768. CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
  1769. if (!free_particles)
  1770. return;
  1771. p = free_particles;
  1772. free_particles = p->next;
  1773. p->next = active_particles;
  1774. active_particles = p;
  1775. p->time = cg.time;
  1776. p->alpha = 1.0;
  1777. p->alphavel = 0;
  1778. p->roll = rand()%179;
  1779. p->pshader = pshader;
  1780. if (duration > 0)
  1781. p->endtime = cg.time + duration;
  1782. else
  1783. p->endtime = duration;
  1784. p->startfade = cg.time;
  1785. p->width = size;
  1786. p->height = size;
  1787. p->endheight = size;
  1788. p->endwidth = size;
  1789. p->type = P_SPRITE;
  1790. VectorCopy( origin, p->org );
  1791. p->rotate = qfalse;
  1792. }