From 245fea051e5152b458e92e66d5c23a13da4a7a20 Mon Sep 17 00:00:00 2001 From: leilei- Date: Tue, 1 Nov 2016 03:30:15 -0400 Subject: [PATCH] Renderer-based particle system (#25) * A WIP particle system * - Some more particle refactoring - an attempt to fix things that went wrong - trying to integrate fog onto particles (which is currently wrong) - qpal.h committed (oops) - Attempt to separate particle rendering from particle moving for future optimization/refactor --- Makefile | 2 + code/cgame/cg_public.h | 3 +- code/cgame/cg_syscalls.asm | 2 +- code/client/cl_cgame.c | 3 + code/renderer_oa/qpal.h | 260 +++ code/renderer_oa/tr_backend.c | 31 +- code/renderer_oa/tr_init.c | 14 +- code/renderer_oa/tr_local.h | 53 +- code/renderer_oa/tr_particles.c | 3171 +++++++++++++++++++++++++++++++ code/renderer_oa/tr_shader.c | 3 + code/renderercommon/tr_public.h | 2 + code/renderergl1/tr_init.c | 1 + code/renderergl2/tr_init.c | 1 + misc/quake3.ico | Bin 2734 -> 10134 bytes 14 files changed, 3530 insertions(+), 16 deletions(-) create mode 100644 code/renderer_oa/qpal.h create mode 100644 code/renderer_oa/tr_particles.c diff --git a/Makefile b/Makefile index ec86aaa9..3243788b 100644 --- a/Makefile +++ b/Makefile @@ -1742,6 +1742,7 @@ Q3ROAOBJ = \ \ $(B)/renderer_oa/tr_bloom.o \ $(B)/renderer_oa/tr_extensions.o \ + $(B)/renderer_oa/tr_particles.o \ \ $(B)/renderergl1/sdl_gamma.o \ $(B)/renderergl1/sdl_glimp.o @@ -1816,6 +1817,7 @@ Q3RSOFTOBJ = \ \ $(B)/renderer_oa/tr_bloom.o \ $(B)/renderer_oa/tr_extensions.o \ + $(B)/renderer_oa/tr_particles.o \ \ $(B)/renderersoft/sdl_gamma.o \ $(B)/renderersoft/sdl_glimp.o diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index 7449d38e..caefff0a 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -182,7 +182,8 @@ typedef enum { CG_CEIL, CG_TESTPRINTINT, CG_TESTPRINTFLOAT, - CG_ACOS + CG_ACOS, + CG_R_LFX_PARTICLEEFFECT // leilei - particle effects } cgameImport_t; diff --git a/code/cgame/cg_syscalls.asm b/code/cgame/cg_syscalls.asm index 0874b479..f6f8d9ef 100644 --- a/code/cgame/cg_syscalls.asm +++ b/code/cgame/cg_syscalls.asm @@ -103,4 +103,4 @@ equ ceil -109 equ testPrintInt -110 equ testPrintFloat -111 equ acos -112 - +equ trap_R_LFX_ParticleEffect -113 diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index d1e84806..31a6a4d9 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -634,6 +634,9 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { return FloatAsInt( ceil( VMF(1) ) ); case CG_ACOS: return FloatAsInt( Q_acos( VMF(1) ) ); + case CG_R_LFX_PARTICLEEFFECT: + re.LFX_ParticleEffect( args[1], VMA(2), VMA(3)); + return 0; case CG_PC_ADD_GLOBAL_DEFINE: return botlib_export->PC_AddGlobalDefine( VMA(1) ); diff --git a/code/renderer_oa/qpal.h b/code/renderer_oa/qpal.h new file mode 100644 index 00000000..32edab00 --- /dev/null +++ b/code/renderer_oa/qpal.h @@ -0,0 +1,260 @@ + +// Quake palette for the Qarticles +static float qpalette[256][3] = { + {0.000000, 0.000000, 0.000000}, + {0.058824, 0.058824, 0.058824}, + {0.121569, 0.121569, 0.121569}, + {0.184314, 0.184314, 0.184314}, + {0.247059, 0.247059, 0.247059}, + {0.294118, 0.294118, 0.294118}, + {0.356863, 0.356863, 0.356863}, + {0.419608, 0.419608, 0.419608}, + {0.482353, 0.482353, 0.482353}, + {0.545098, 0.545098, 0.545098}, + {0.607843, 0.607843, 0.607843}, + {0.670588, 0.670588, 0.670588}, + {0.733333, 0.733333, 0.733333}, + {0.796078, 0.796078, 0.796078}, + {0.858824, 0.858824, 0.858824}, + {0.921569, 0.921569, 0.921569}, + {0.058824, 0.043137, 0.027451}, + {0.090196, 0.058824, 0.043137}, + {0.121569, 0.090196, 0.043137}, + {0.152941, 0.105882, 0.058824}, + {0.184314, 0.137255, 0.074510}, + {0.215686, 0.168627, 0.090196}, + {0.247059, 0.184314, 0.090196}, + {0.294118, 0.215686, 0.105882}, + {0.325490, 0.231373, 0.105882}, + {0.356863, 0.262745, 0.121569}, + {0.388235, 0.294118, 0.121569}, + {0.419608, 0.325490, 0.121569}, + {0.450980, 0.341176, 0.121569}, + {0.482353, 0.372549, 0.137255}, + {0.513725, 0.403922, 0.137255}, + {0.560784, 0.435294, 0.137255}, + {0.043137, 0.043137, 0.058824}, + {0.074510, 0.074510, 0.105882}, + {0.105882, 0.105882, 0.152941}, + {0.152941, 0.152941, 0.200000}, + {0.184314, 0.184314, 0.247059}, + {0.215686, 0.215686, 0.294118}, + {0.247059, 0.247059, 0.341176}, + {0.278431, 0.278431, 0.403922}, + {0.309804, 0.309804, 0.450980}, + {0.356863, 0.356863, 0.498039}, + {0.388235, 0.388235, 0.545098}, + {0.419608, 0.419608, 0.592157}, + {0.450980, 0.450980, 0.639216}, + {0.482353, 0.482353, 0.686275}, + {0.513725, 0.513725, 0.733333}, + {0.545098, 0.545098, 0.796078}, + {0.000000, 0.000000, 0.000000}, + {0.027451, 0.027451, 0.000000}, + {0.043137, 0.043137, 0.000000}, + {0.074510, 0.074510, 0.000000}, + {0.105882, 0.105882, 0.000000}, + {0.137255, 0.137255, 0.000000}, + {0.168627, 0.168627, 0.027451}, + {0.184314, 0.184314, 0.027451}, + {0.215686, 0.215686, 0.027451}, + {0.247059, 0.247059, 0.027451}, + {0.278431, 0.278431, 0.027451}, + {0.294118, 0.294118, 0.043137}, + {0.325490, 0.325490, 0.043137}, + {0.356863, 0.356863, 0.043137}, + {0.388235, 0.388235, 0.043137}, + {0.419608, 0.419608, 0.058824}, + {0.027451, 0.000000, 0.000000}, + {0.058824, 0.000000, 0.000000}, + {0.090196, 0.000000, 0.000000}, + {0.121569, 0.000000, 0.000000}, + {0.152941, 0.000000, 0.000000}, + {0.184314, 0.000000, 0.000000}, + {0.215686, 0.000000, 0.000000}, + {0.247059, 0.000000, 0.000000}, + {0.278431, 0.000000, 0.000000}, + {0.309804, 0.000000, 0.000000}, + {0.341176, 0.000000, 0.000000}, + {0.372549, 0.000000, 0.000000}, + {0.403922, 0.000000, 0.000000}, + {0.435294, 0.000000, 0.000000}, + {0.466667, 0.000000, 0.000000}, + {0.498039, 0.000000, 0.000000}, + {0.074510, 0.074510, 0.000000}, + {0.105882, 0.105882, 0.000000}, + {0.137255, 0.137255, 0.000000}, + {0.184314, 0.168627, 0.000000}, + {0.215686, 0.184314, 0.000000}, + {0.262745, 0.215686, 0.000000}, + {0.294118, 0.231373, 0.027451}, + {0.341176, 0.262745, 0.027451}, + {0.372549, 0.278431, 0.027451}, + {0.419608, 0.294118, 0.043137}, + {0.466667, 0.325490, 0.058824}, + {0.513725, 0.341176, 0.074510}, + {0.545098, 0.356863, 0.074510}, + {0.592157, 0.372549, 0.105882}, + {0.639216, 0.388235, 0.121569}, + {0.686275, 0.403922, 0.137255}, + {0.137255, 0.074510, 0.027451}, + {0.184314, 0.090196, 0.043137}, + {0.231373, 0.121569, 0.058824}, + {0.294118, 0.137255, 0.074510}, + {0.341176, 0.168627, 0.090196}, + {0.388235, 0.184314, 0.121569}, + {0.450980, 0.215686, 0.137255}, + {0.498039, 0.231373, 0.168627}, + {0.560784, 0.262745, 0.200000}, + {0.623529, 0.309804, 0.200000}, + {0.686275, 0.388235, 0.184314}, + {0.749020, 0.466667, 0.184314}, + {0.811765, 0.560784, 0.168627}, + {0.874510, 0.670588, 0.152941}, + {0.937255, 0.796078, 0.121569}, + {1.000000, 0.952941, 0.105882}, + {0.043137, 0.027451, 0.000000}, + {0.105882, 0.074510, 0.000000}, + {0.168627, 0.137255, 0.058824}, + {0.215686, 0.168627, 0.074510}, + {0.278431, 0.200000, 0.105882}, + {0.325490, 0.215686, 0.137255}, + {0.388235, 0.247059, 0.168627}, + {0.435294, 0.278431, 0.200000}, + {0.498039, 0.325490, 0.247059}, + {0.545098, 0.372549, 0.278431}, + {0.607843, 0.419608, 0.325490}, + {0.654902, 0.482353, 0.372549}, + {0.717647, 0.529412, 0.419608}, + {0.764706, 0.576471, 0.482353}, + {0.827451, 0.639216, 0.545098}, + {0.890196, 0.701961, 0.592157}, + {0.670588, 0.545098, 0.639216}, + {0.623529, 0.498039, 0.592157}, + {0.576471, 0.450980, 0.529412}, + {0.545098, 0.403922, 0.482353}, + {0.498039, 0.356863, 0.435294}, + {0.466667, 0.325490, 0.388235}, + {0.419608, 0.294118, 0.341176}, + {0.372549, 0.247059, 0.294118}, + {0.341176, 0.215686, 0.262745}, + {0.294118, 0.184314, 0.215686}, + {0.262745, 0.152941, 0.184314}, + {0.215686, 0.121569, 0.137255}, + {0.168627, 0.090196, 0.105882}, + {0.137255, 0.074510, 0.074510}, + {0.090196, 0.043137, 0.043137}, + {0.058824, 0.027451, 0.027451}, + {0.733333, 0.450980, 0.623529}, + {0.686275, 0.419608, 0.560784}, + {0.639216, 0.372549, 0.513725}, + {0.592157, 0.341176, 0.466667}, + {0.545098, 0.309804, 0.419608}, + {0.498039, 0.294118, 0.372549}, + {0.450980, 0.262745, 0.325490}, + {0.419608, 0.231373, 0.294118}, + {0.372549, 0.200000, 0.247059}, + {0.325490, 0.168627, 0.215686}, + {0.278431, 0.137255, 0.168627}, + {0.231373, 0.121569, 0.137255}, + {0.184314, 0.090196, 0.105882}, + {0.137255, 0.074510, 0.074510}, + {0.090196, 0.043137, 0.043137}, + {0.058824, 0.027451, 0.027451}, + {0.858824, 0.764706, 0.733333}, + {0.796078, 0.701961, 0.654902}, + {0.749020, 0.639216, 0.607843}, + {0.686275, 0.592157, 0.545098}, + {0.639216, 0.529412, 0.482353}, + {0.592157, 0.482353, 0.435294}, + {0.529412, 0.435294, 0.372549}, + {0.482353, 0.388235, 0.325490}, + {0.419608, 0.341176, 0.278431}, + {0.372549, 0.294118, 0.231373}, + {0.325490, 0.247059, 0.200000}, + {0.262745, 0.200000, 0.152941}, + {0.215686, 0.168627, 0.121569}, + {0.152941, 0.121569, 0.090196}, + {0.105882, 0.074510, 0.058824}, + {0.058824, 0.043137, 0.027451}, + {0.435294, 0.513725, 0.482353}, + {0.403922, 0.482353, 0.435294}, + {0.372549, 0.450980, 0.403922}, + {0.341176, 0.419608, 0.372549}, + {0.309804, 0.388235, 0.341176}, + {0.278431, 0.356863, 0.309804}, + {0.247059, 0.325490, 0.278431}, + {0.215686, 0.294118, 0.247059}, + {0.184314, 0.262745, 0.215686}, + {0.168627, 0.231373, 0.184314}, + {0.137255, 0.200000, 0.152941}, + {0.121569, 0.168627, 0.121569}, + {0.090196, 0.137255, 0.090196}, + {0.058824, 0.105882, 0.074510}, + {0.043137, 0.074510, 0.043137}, + {0.027451, 0.043137, 0.027451}, + {1.000000, 0.952941, 0.105882}, + {0.937255, 0.874510, 0.090196}, + {0.858824, 0.796078, 0.074510}, + {0.796078, 0.717647, 0.058824}, + {0.733333, 0.654902, 0.058824}, + {0.670588, 0.592157, 0.043137}, + {0.607843, 0.513725, 0.027451}, + {0.545098, 0.450980, 0.027451}, + {0.482353, 0.388235, 0.027451}, + {0.419608, 0.325490, 0.000000}, + {0.356863, 0.278431, 0.000000}, + {0.294118, 0.215686, 0.000000}, + {0.231373, 0.168627, 0.000000}, + {0.168627, 0.121569, 0.000000}, + {0.105882, 0.058824, 0.000000}, + {0.043137, 0.027451, 0.000000}, + {0.000000, 0.000000, 1.000000}, + {0.043137, 0.043137, 0.937255}, + {0.074510, 0.074510, 0.874510}, + {0.105882, 0.105882, 0.811765}, + {0.137255, 0.137255, 0.749020}, + {0.168627, 0.168627, 0.686275}, + {0.184314, 0.184314, 0.623529}, + {0.184314, 0.184314, 0.560784}, + {0.184314, 0.184314, 0.498039}, + {0.184314, 0.184314, 0.435294}, + {0.184314, 0.184314, 0.372549}, + {0.168627, 0.168627, 0.309804}, + {0.137255, 0.137255, 0.247059}, + {0.105882, 0.105882, 0.184314}, + {0.074510, 0.074510, 0.121569}, + {0.043137, 0.043137, 0.058824}, + {0.168627, 0.000000, 0.000000}, + {0.231373, 0.000000, 0.000000}, + {0.294118, 0.027451, 0.000000}, + {0.372549, 0.027451, 0.000000}, + {0.435294, 0.058824, 0.000000}, + {0.498039, 0.090196, 0.027451}, + {0.576471, 0.121569, 0.027451}, + {0.639216, 0.152941, 0.043137}, + {0.717647, 0.200000, 0.058824}, + {0.764706, 0.294118, 0.105882}, + {0.811765, 0.388235, 0.168627}, + {0.858824, 0.498039, 0.231373}, + {0.890196, 0.592157, 0.309804}, + {0.905882, 0.670588, 0.372549}, + {0.937255, 0.749020, 0.466667}, + {0.968627, 0.827451, 0.545098}, + {0.654902, 0.482353, 0.231373}, + {0.717647, 0.607843, 0.215686}, + {0.780392, 0.764706, 0.215686}, + {0.905882, 0.890196, 0.341176}, + {0.498039, 0.749020, 1.000000}, + {0.670588, 0.905882, 1.000000}, + {0.843137, 1.000000, 1.000000}, + {0.403922, 0.000000, 0.000000}, + {0.545098, 0.000000, 0.000000}, + {0.701961, 0.000000, 0.000000}, + {0.843137, 0.000000, 0.000000}, + {1.000000, 0.000000, 0.000000}, + {1.000000, 0.952941, 0.576471}, + {1.000000, 0.968627, 0.780392}, + {1.000000, 1.000000, 1.000000}, + {0.623529, 0.356863, 0.325490} +}; diff --git a/code/renderer_oa/tr_backend.c b/code/renderer_oa/tr_backend.c index dac9768a..33e006ca 100644 --- a/code/renderer_oa/tr_backend.c +++ b/code/renderer_oa/tr_backend.c @@ -1035,6 +1035,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // darken down any stencil shadows RB_ShadowFinish(); + // add the particles + //R_AddParticles (); + R_RenderParticles (); + // add light flares on lights that aren't obscured RB_RenderFlares(); @@ -1543,15 +1547,19 @@ float mblur_timelast; float time_now; float time_last; float mbluracc; +int mblurredframes; +int mblurredframestotal; void RB_AccumBlurValue (void) { + int ah, tim, oltim; + oltim = time_last * 10; + tim = time_now * 10; // calculate how much we need, determined by motion blur fps mblur_time = time_now - time_last; mbluracc = (mblur_time) / 32; mbluracc *= -1; mbluracc += 1.0f; mbluracc /= 2; - }; void RB_DrawAccumBlur (void) @@ -1568,8 +1576,8 @@ void RB_DrawAccumBlur (void) accblur = mbluracc; //ri.Printf( PRINT_WARNING, "accum value %f\n", mbluracc ); - if (accblur > 1.0f) - accblur = 0.5f; +// if (accblur > 1.0f) +// accblur = 0.5f; if (accblur <= 0.0f) { @@ -1586,6 +1594,7 @@ void RB_DrawAccumBlur (void) } else { + qglAccum (GL_LOAD, 1.0f); qglAccum (GL_MULT, accblur); // scale contents of accumulation buffer qglAccum (GL_ACCUM, 1.0f - accblur); // add screen contents qglAccum (GL_RETURN, 1.0f); // read result back @@ -1603,7 +1612,6 @@ RB_SwapBuffers const void *RB_SwapBuffers( const void *data ) { const swapBuffersCommand_t *cmd; - // finish any 2D drawing if needed if ( tess.numIndexes ) { @@ -1637,7 +1645,9 @@ const void *RB_SwapBuffers( const void *data ) { if (r_motionblur->integer == 1){ RB_DrawAccumBlur (); + } + R_BrightScreen(); // leilei - alternate brightness - do it here so we hit evereything that represents our video buffer @@ -1695,7 +1705,13 @@ const void *RB_SwapBuffers( const void *data ) { backEnd.donentsc = qfalse; backEnd.donetv = qfalse; backEnd.doneraa = qfalse; - + backEnd.doneParticles = qfalse; + + // leilei - only reset this every 15hz to keep it fast and synchronized + if (backEnd.refdef.time > backEnd.flareTestTime){ + backEnd.doneFlareTests = qfalse; + backEnd.flareTestTime = backEnd.refdef.time + 100.0f; + } // leilei - artificial slowness (mapper debug) - this might be windows only #ifdef _WIN32 @@ -1749,11 +1765,9 @@ void RB_ExecuteRenderCommands( const void *data ) { case RC_STRETCH_PIC: //Check if it's time for BLOOM! leifxmode = 0; - R_WaterScreen(); // do this first R_PostprocessScreen(); R_BloomScreen(); R_FilmScreen(); - R_AnimeScreen(); data = RB_StretchPic( data ); break; case RC_DRAW_SURFS: @@ -1765,12 +1779,9 @@ void RB_ExecuteRenderCommands( const void *data ) { case RC_SWAP_BUFFERS: //Check if it's time for BLOOM! leifxmode = 0; - R_WaterScreen(); // do this first R_PostprocessScreen(); R_BloomScreen(); R_FilmScreen(); - R_AnimeScreen(); - data = RB_SwapBuffers( data ); break; case RC_SCREENSHOT: diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index cfdd4728..c9f34e9b 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -196,6 +196,7 @@ cvar_t *r_flareMethod; // method of flare intensity cvar_t *r_flareQuality; // testing quality of the flares. cvar_t *r_flareSun; // type of flare to use for the sun cvar_t *r_flareDelay; // time delay for medium quality flare testing +cvar_t *r_flaresMotionBlur; // Stretch blur cvar_t *r_specMode; //cvar_t *r_waveMode; @@ -210,6 +211,7 @@ cvar_t *r_mockvr; // Leilei - for debugging PVR only! cvar_t *r_parseStageSimple; // Leilei - for debugging PVR only! cvar_t *r_leifx; // Leilei - leifx nostalgia filter cvar_t *r_modelshader; // Leilei +cvar_t *r_particles; // Leilei - particle effects motif cvar_t *r_ntsc; // Leilei - ntsc / composite signals //cvar_t *r_tvMode; // Leilei - tv fake mode @@ -1314,7 +1316,7 @@ void R_Register( void ) r_lensReflection2 = ri.Cvar_Get( "r_lensReflection2", "0" , CVAR_ARCHIVE); // fuzzy reflection r_lensReflectionBrightness = ri.Cvar_Get( "r_lensReflectionBrightness", "0.5" , CVAR_ARCHIVE); - r_flareQuality = ri.Cvar_Get( "r_flareQuality", "1" , CVAR_ARCHIVE); // use medium flares for default + r_flareQuality = ri.Cvar_Get( "r_flareQuality", "4" , CVAR_ARCHIVE); // use high flares for default (lower settings stutter vsync or clip too badly) r_flareMethod = ri.Cvar_Get( "r_flareMethod", "0" , CVAR_ARCHIVE); r_flaresDlight = ri.Cvar_Get( "r_flaresDlight", "0" , CVAR_ARCHIVE ); // dynamic light flares r_flaresDlightShrink = ri.Cvar_Get( "r_flaresDlightShrink", "1" , CVAR_ARCHIVE ); // dynamic light flares shrinking when close (reducing muzzleflash blindness) @@ -1324,6 +1326,9 @@ void R_Register( void ) r_flareSun = ri.Cvar_Get( "r_flareSun", "0" , CVAR_ARCHIVE); // it's 0 because mappers expect 0. r_flareDelay = ri.Cvar_Get( "r_flareDelay", "100" , CVAR_CHEAT); // update delay for flare pixel read checking. + r_flaresMotionBlur = ri.Cvar_Get( "r_flaresMotionBlur", "0" , CVAR_ARCHIVE ); // fake motion blur on flares + + r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_CHEAT); r_parseStageSimple = ri.Cvar_Get( "r_parseStageSimple", "0" , CVAR_CHEAT); @@ -1345,6 +1350,7 @@ void R_Register( void ) r_anime = ri.Cvar_Get( "r_anime", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_palletize = ri.Cvar_Get( "r_palletize", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_leidebug = ri.Cvar_Get( "r_leidebug", "0" , CVAR_CHEAT); + r_particles = ri.Cvar_Get( "r_particles", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_leidebugeye = ri.Cvar_Get( "r_leidebugeye", "0" , CVAR_CHEAT); r_slowness = ri.Cvar_Get( "r_slowness", "0" , CVAR_ARCHIVE); // it's 0 because you want it to be the fastest possible by default. r_slowness_cpu = ri.Cvar_Get( "r_slowness_cpu", "300" , CVAR_ARCHIVE); // it's 0 because you want it to be the fastest possible by default. @@ -1557,7 +1563,7 @@ void R_GLSL_Init(void) { } #endif } - +extern qboolean initparticles; /* =============== @@ -1650,7 +1656,8 @@ void R_Init( void ) { R_ModelInit(); R_InitFreeType(); - + + err = qglGetError(); if ( err != GL_NO_ERROR ) ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); @@ -1763,6 +1770,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { re.ClearScene = RE_ClearScene; re.AddRefEntityToScene = RE_AddRefEntityToScene; re.AddPolyToScene = RE_AddPolyToScene; + re.LFX_ParticleEffect = LFX_ParticleEffect; re.LightForPoint = R_LightForPoint; re.AddLightToScene = RE_AddLightToScene; re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index 9c47b4c8..dfeb0b8d 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -153,7 +153,8 @@ typedef enum { DEFORM_TEXT4, DEFORM_TEXT5, DEFORM_TEXT6, - DEFORM_TEXT7 + DEFORM_TEXT7, + DEFORM_LFX } deform_t; typedef enum { @@ -221,6 +222,25 @@ typedef struct { float frequency; } waveForm_t; +typedef struct { + int lfxtype; // ... later +/* + int amount; + int radiusmode; + float radius + + float minsize + float maxsize + float r + vec3_t vel; + vec3_t org; + float spread; + int blend; + int shader; +*/ +} lfx_t; + + // leilei - texture atlases typedef struct { float width; // columns @@ -257,6 +277,8 @@ typedef struct { float bulgeWidth; float bulgeHeight; float bulgeSpeed; + + lfx_t deformationLfx; } deformStage_t; @@ -1090,6 +1112,9 @@ typedef struct { qboolean donentsc; // leilei - done ntsc'ing this frame qboolean donepalette; // leilei - done animeing this frame qboolean doneSurfaces; // done any 3d surfaces already + qboolean doneParticles; // done any particle movement + qboolean doneFlareTests; // leilei - done testing flares + float flareTestTime; trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering } backEndState_t; @@ -1232,6 +1257,8 @@ typedef struct { qboolean placeholderFogAvail; qboolean placeholderAvail; + + } trGlobals_t; extern backEndState_t backEnd; @@ -1369,6 +1396,8 @@ extern cvar_t *r_flaresDlightShrink; extern cvar_t *r_flaresDlightFade; extern cvar_t *r_flaresDlightOpacity; extern cvar_t *r_flaresDlightScale; + +extern cvar_t *r_flaresMotionBlur; //extern cvar_t *r_flaresSurfradii; extern cvar_t *r_alternateBrightness; // leilei - alternate brightness @@ -1395,6 +1424,7 @@ extern cvar_t *r_anime; // Leilei - anime filter extern cvar_t *r_palletize; // Leilei - anime filter extern cvar_t *r_leidebug; // Leilei - debug only! extern cvar_t *r_leidebugeye; // Leilei - debug only! +extern cvar_t *r_particles; // Leilei - particles! extern cvar_t *r_iconmip; // leilei - icon mip - picmip for 2d icons extern cvar_t *r_iconBits; // leilei - icon color depth for 2d icons @@ -1580,6 +1610,10 @@ typedef struct shaderCommands_s int numPasses; void (*currentStageIteratorFunc)( void ); shaderStage_t **xstages; + + // lfx stuf + float lfxTime; + float lfxTimeNext; } shaderCommands_t; extern shaderCommands_t tess; @@ -2335,5 +2369,22 @@ extern int voodootype; // 0 - none 1 - Voodoo Graphics 2 - Voodoo2, 3 - Voodoo B void RB_UpdateMotionBlur (void); void R_MotionBlur_BackupScreen(int which); + +void R_AddParticles (void); +void R_RenderParticles (void); +void R_ClearParticles (void); +void R_LFX_Spark (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc); +void R_LFX_Smoke (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc); +void R_LFX_Smoke2 (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scale, float scaleup, int blendfunc); +void R_LFX_Shock (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc); +void R_LFX_Burst (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc); +void R_LFX_PushSmoke (vec3_t there, float force); + +void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count); +void R_QarticleExplosion(vec3_t org); +void R_LFX_Blood (vec3_t org, vec3_t dir, float pressure) ; +void LFX_ShaderInit(void); +void LFX_ParticleEffect (int effect, vec3_t org, vec3_t dir); + #endif //TR_LOCAL_H diff --git a/code/renderer_oa/tr_particles.c b/code/renderer_oa/tr_particles.c new file mode 100644 index 00000000..56ac46c8 --- /dev/null +++ b/code/renderer_oa/tr_particles.c @@ -0,0 +1,3171 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "tr_local.h" +#include "qpal.h" +#include "../qcommon/cm_local.h" +#include "../qcommon/cm_public.h" + +// +// LEILEI'S PARTICLES! +// + +// partially ported out of cg_marks.c +// and heavily improved upon + +#define BLOODRED 2 +#define EMISIVEFADE 3 +#define GREY75 4 + +#define BLOODRED 2 +#define EMISIVEFADE 3 +#define LFXSTUFF 1 +#define LFXSHOCK 2 +#define LFXSMOKE 3 +#define LFXSPARK 4 +#define LFXBURST 5 +#define LFXLIQUID 6 +#define LFXSTRAND 7 +#define LFXTRAIL 8 +#define LFXBUBBLE 9 +#define LFXQUAKE 10 + + +// color types + +#define P_LFX 1 // ramp +#define P_LFXSIMPLE 2 // solid color +#define P_INDEXED 3 // indexed color from qpal + + +#define MAX_TRAIL_POINTS 8 +#define TRAIL_LENGTH_SPLIT 64 + +typedef struct particle_s +{ + struct particle_s *next; + + float time; + float endtime; + + vec3_t org; + vec3_t vel; + vec3_t accel; + int color; + float colorvel; + float alpha; + float alphavel; + int type; + shader_t *pshader; + + float height; + float width; + + float endheight; + float endwidth; + + float start; + float end; + + float startfade; + qboolean rotate; + int snum; + + qboolean link; + + // Ridah + int shaderAnim; + int roll; + + int accumroll; + + // leilei + float stretch; + vec3_t angle; + vec3_t avelocity; + vec3_t src; + vec3_t dest; + float airfriction; + float rollfriction; + int qolor; // quake palette color translation + int ramp; // quake color ramping (rocket trails, explosion) + + float cols[4][5]; // fading color cycle + vec3_t dir; // angle, direction + float rollvel; // velocity of roll + float bounce; // how much elasticity does it have + vec3_t torg[MAX_TRAIL_POINTS]; // extra origins to use for trails and bursts + int active_trail; // how many trail points are active on this trail + int bubbleit; // turn into a bubble when crossing into water. + int material; // kind of material it is? + + float die; // quake translation + + int rendertype; // particle type (spark, oriented, etc) + int colortype; // color type (ramp, palette, singular) + int fogNum; +} particle_t; + +void R_AddParticleToScene (particle_t *p, vec3_t org, float alpha); +void R_LetsBounce ( particle_t *p); + +// Shaders + +static shader_t *addshock; +static shader_t *subshock; +static shader_t *modshock; +static shader_t *alfshock; + +static shader_t *addball; +static shader_t *subball; +static shader_t *modball; +static shader_t *alfball; + + +static shader_t *blood1; +static shader_t *blood2; + +static shader_t *watsplash; +static shader_t *watburst; +static shader_t *watbubble; + +static shader_t *fireball; + +static shader_t *addsmoke; +static shader_t *subsmoke; +static shader_t *modsmoke; +static shader_t *alfsmoke; + + + +#define MAX_ENTITIES 500 + + +// more quake stuff + + +static int ramp1[8] = { 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61 }; +static int ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 }; +static int ramp3[8] = { 0x6d, 0x6b, 6, 5, 4, 3 }; + + + +typedef enum +{ + P_NONE, + P_WEATHER, + P_FLAT, + P_SMOKE, + P_ROTATE, + P_WEATHER_TURBULENT, + P_ANIM, // Ridah + P_BAT, + P_BLEED, + P_FLAT_SCALEUP, + P_FLAT_SCALEUP_FADE, + P_WEATHER_FLURRY, + P_SMOKE_IMPACT, + P_BUBBLE, + P_BUBBLE_TURBULENT, + P_SPRITE, + P_BEAM, // leilei - angle not calculated + P_SPARK, // leilei - angle and length recalculated from velocity + P_QUAKESTATIC, + P_QUAKEGRAV, + P_QUAKESLOWGRAV, + P_QUAKEFIRE, + P_QUAKEEXPLODE, + P_QUAKEEXPLODE2, + P_QUAKEBLOB, + P_QUAKEBLOB2, + P_QUAKE +} particle_type_t; + + + + +#define MAX_SHADER_ANIMS 32 +#define MAX_SHADER_ANIM_FRAMES 64 + +static int numShaderAnims; +// done. + +#define PARTICLE_GRAVITY 40 +#define MAX_PARTICLES 2048 // 1000000 // we can do CRAZY amounts of particles. but let's be sensible + +particle_t *active_particles, *free_particles; +particle_t particles[MAX_PARTICLES]; +int cl_numparticles = MAX_PARTICLES; + +qboolean initparticles = qfalse; +static vec3_t pvforward, pvright, pvup; +static vec3_t rforward, rright, rup; + +static float oldTime; + + +static float THEtime; + +// lazy struct hack to make quake code backporting quicker and painless + +typedef struct +{ + double time; +} imlazy_t; + +static imlazy_t cl; + +#define pt_grav P_QUAKEGRAV +#define pt_slowgrav P_QUAKESLOWGRAV +#define pt_static P_QUAKESTATIC +#define pt_explode P_QUAKEEXPLODE +#define pt_explode2 P_QUAKEEXPLODE2 +#define pt_blob P_QUAKEBLOB +#define pt_blob2 P_QUAKEBLOB2 +#define pt_fire P_QUAKEFIRE + +void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, + clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere ); + +static void P_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, + int skipNumber, int mask ) { + + CM_Trace(result, start, end, NULL, NULL, 0, start, mask, 0, NULL); +} + +/* +=============== +R_ClearParticles +=============== +*/ +void R_ClearParticles (void) +{ + int i; + + memset( particles, 0, sizeof(particles) ); + + free_particles = &particles[0]; + active_particles = NULL; + + for (i=0 ;icols[0][0], p->cols[1][0], p->cols[2][0]); + THEtime = backEnd.refdef.time; + + // qarticle transitions + cl.time = THEtime / 10; // quarticles + + + + time = THEtime- p->time; + time2 = p->endtime - p->time; + ratio = time / time2; + + // Do us some fogging fogger + { + byte fogFactors[3] = {255, 255, 255}; + if(tr.world && p->fogNum > 0 && p->fogNum < tr.world->numfogs) + { + tess.numVertexes = 1; + VectorCopy(org, tess.xyz[0]); + tess.fogNum = p->fogNum; + + RB_CalcModulateColorsByFog(fogFactors); + + } + } + + + + {// create a front rotating facing polygon + // that can change colors + // and........ something. + vec3_t rr, ru; + vec3_t rotate_ang; + + if (p->colortype == P_LFX){ // Ramp + + // hack to prevent that one long particle from going crazy in the world. + if (p->startfade > THEtime){ + + p->bounce = 0; p->bubbleit = 0; //no cpu expensive checks + return; + + } + + + if (THEtime> p->startfade) + { + float inv1,inv2,inv3,inv4; + invratio = 1 - ( (THEtime- p->startfade) / (p->endtime - p->startfade) ); + + inv1 = invratio * 4.0; + inv2 = invratio * 4.0 - 1; + inv3 = invratio * 4.0 - 2; + inv4 = invratio * 4.0 - 3; + + if (inv1 > 1.0f) inv1 = 1.0f; + if (inv2 > 1.0f) inv2 = 1.0f; + if (inv3 > 1.0f) inv3 = 1.0f; + if (inv4 > 1.0f) inv4 = 1.0f; + + + { + int et; + vec4_t fcol; + + for(et=0;et<4;et++) + { + + + if (invratio < 0.25f) + fcol[et] = (p->cols[et][3] * inv1) + (p->cols[et][4] * (1 - inv1)); + else if (invratio < 0.50f) + fcol[et] = (p->cols[et][2] * inv2) + (p->cols[et][3] * (1 - inv2)); + else if (invratio < 0.75f) + fcol[et] = (p->cols[et][1] * inv3) + (p->cols[et][2] * (1 - inv3)); + else + fcol[et] = (p->cols[et][0] * inv4) + (p->cols[et][1] * (1 - inv4)); + + + } + + + for(et=0;et<4;et++){ + if (fcol[et]>1)fcol[et]=1.0f; + if (fcol[et]<0)fcol[et]=0.0f; + } + + + + + color[0] = fcol[0]; + color[1] = fcol[1]; + color[2] = fcol[2]; + color[3] = fcol[3]; + + + } + + } + + if (invratio > 4) + invratio = 4; + } + else if (p->colortype = P_INDEXED) + { + VectorSet(color, qpalette[p->qolor][0], qpalette[p->qolor][1], qpalette[p->qolor][2]); + color[3] = 1.0f; + } + else // simple + { + invratio = 1; + color[0] = p->cols[0][0]; + color[1] = p->cols[1][0]; + color[2] = p->cols[2][0]; + color[3] = p->alpha; + + } + + if (p->rendertype == LFXSHOCK) + { // ORIENTED sprite - used for shockwaves, water waves, waves, etc. + vec3_t argles; + vec3_t right, up; + int ind=0; + vectoangles( p->dir, argles ); + AngleVectors ( argles, NULL, right, up); + + width = p->width + ( ratio * ( p->endwidth - p->width) ); + height = p->height + ( ratio * ( p->endheight - p->height) ); + + if (p->roll) { + vectoangles( p->dir, rotate_ang ); + rotate_ang[ROLL] += p->roll; + AngleVectors ( rotate_ang, NULL, right, up); + } + + RB_BeginSurface( p->pshader, fogNum ); + VectorMA (org, -height, right, point); + VectorMA (point, -width, up, point); + + + + VectorCopy (point, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + VectorMA( point, 2*height, up, point); + VectorCopy (point, tess.xyz[tess.numVertexes]); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + + VectorMA( point, 2*width, right, point ); + VectorCopy (point, tess.xyz[tess.numVertexes]); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + + VectorMA( point, -2*height, up, point ); + VectorCopy (point, tess.xyz[tess.numVertexes]); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 1; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 3; + + ind+=4; + RB_EndSurface(); + + } + else if (p->rendertype == LFXSPARK) + { // STRETCHY SPARK sprite - used for sparks etc + vec3_t argles; + vec3_t right, up, fwd; + vec3_t line; + float len, begin, end; + vec3_t start, finish; + int ind=0; + vec3_t oldorgstretch; + vectoangles( p->dir, argles ); + AngleVectors ( argles, NULL, right, up); + + // Set up the 'beam' + + + oldorgstretch[0] = org[0] + ((p->vel[0] ) * 0.005); + oldorgstretch[1] = org[1] + ((p->vel[1]) * 0.005); + oldorgstretch[2] = org[2] + ((p->vel[2] ) * 0.005); + + + VectorSubtract( org, oldorgstretch, fwd ); + + len = VectorNormalize( fwd ); + //len = DotProduct(p->vel);// * (5 / (THEtime- oldTime)) ; + len *= p->height + p->width; + + len *= 7; // doesn't look good in low framerates :/ + begin = -len / 2; + end = len / 2; + + + + // Set up the particle + + width = p->width + ( ratio * ( p->endwidth - p->width) ); + height = p->height + ( ratio * ( p->endheight - p->height) ); + + + VectorMA( org, begin, fwd, start ); + VectorMA( org, end, fwd, finish ); + + line[0] = DotProduct( fwd, backEnd.refdef.viewaxis[1] ); + line[1] = DotProduct( fwd, backEnd.refdef.viewaxis[2] ); + + VectorScale( backEnd.refdef.viewaxis[1], line[1], right ); + VectorMA( right, -line[0], backEnd.refdef.viewaxis[2], right ); + VectorNormalize( right ); + + RB_BeginSurface( p->pshader, fogNum ); + + VectorMA( finish, width, right, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + VectorMA( finish, -width, right, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + + VectorMA( start, -width, right, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + + VectorMA( start, width, right, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 1; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 3; + + ind+=4; + RB_EndSurface(); + + + // center glow of softness? Enable for 2002 particleset? + + } + else if (p->rendertype == LFXBURST) + { // STRETCHY BURST sprite - used for explosions + // like spark but origin doesnt change. it just keeps stretching + // from where it was spawned. + vec3_t argles; + vec3_t right, up, fwd; + vec3_t line; + float len, begin, end; + vec3_t start, finish; + int ind=0; + vec3_t oldorgstretch; + vectoangles( p->dir, argles ); + AngleVectors ( argles, NULL, right, up); + + // Set up the 'beam' + + + + oldorgstretch[0] = p->torg[0][0]; + oldorgstretch[1] = p->torg[0][1]; + oldorgstretch[2] = p->torg[0][2]; + + + VectorSubtract( org, oldorgstretch, fwd ); + + len = VectorNormalize( fwd ); + //len = DotProduct(p->vel);// * (5 / (THEtime- oldTime)) ; + len *= p->height + p->width; + + len *= 1; // doesn't look good in low framerates :/ + begin = 0; + end = len; + + + + // Set up the particle + + width = p->width + ( ratio * ( p->endwidth - p->width) ); + height = p->height + ( ratio * ( p->endheight - p->height) ); + + + VectorMA( org, begin, fwd, start ); + VectorMA( org, end, fwd, finish ); + + line[0] = DotProduct( fwd, backEnd.refdef.viewaxis[1] ); + line[1] = DotProduct( fwd, backEnd.refdef.viewaxis[2] ); + + VectorScale( backEnd.refdef.viewaxis[1], line[1], right ); + VectorMA( right, -line[0], backEnd.refdef.viewaxis[2], right ); + VectorNormalize( right ); + + RB_BeginSurface( p->pshader, fogNum ); + + VectorMA( finish, width, right, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + VectorMA( finish, -width, right, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + + VectorMA( start, -width, right, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + + VectorMA( start, width, right, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 1; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 3; + + ind+=4; + RB_EndSurface(); + } + + else if (p->rendertype == LFXTRAIL) + { // STRETCHY TRAIL sprite - used for..... i dunno + // like burst but splits into more trails when the certain length is achieved + // TO RETURN + } + + else + // VP PARALLEL sprite + { + // trace_t pt1, pt2, pt3, pt4; + // float avgfrac; + int ind=0; + width = p->width + ( ratio * ( p->endwidth - p->width) ); + height = p->height + ( ratio * ( p->endheight - p->height) ); + + if (p->roll) { + vectoangles( backEnd.refdef.viewaxis[0], rotate_ang ); + rotate_ang[ROLL] += p->roll; + AngleVectors ( rotate_ang, NULL, rr, ru); + } + + if (p->roll) { + VectorMA (org, -height, ru, point); + VectorMA (point, -width, rr, point); + } else { + VectorMA (org, -height, pvup, point); + VectorMA (point, -width, pvright, point); + } + + // Faded clipping test. we don't need dx10 after all :) + + + RB_BeginSurface( p->pshader, fogNum ); + + VectorCopy (point, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + if (p->roll) { + VectorMA (point, 2*height, ru, point); + } else { + VectorMA (point, 2*height, pvup, point); + } + VectorCopy (point, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + if (p->roll) { + VectorMA (point, 2*width, rr, point); + } else { + VectorMA (point, 2*width, pvright, point); + } + VectorCopy (point, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + if (p->roll) { + VectorMA (point, -2*height, ru, point); + } else { + VectorMA (point, -2*height, pvup, point); + } + VectorCopy (point, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255 * color[0]; + tess.vertexColors[tess.numVertexes][1] = 255 * color[1]; + tess.vertexColors[tess.numVertexes][2] = 255 * color[2]; + tess.vertexColors[tess.numVertexes][3] = 255 * invratio; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 1; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 3; + + ind+=4; + RB_EndSurface(); + + } + } + + + if (!p->pshader) { + // force a shader. + p->pshader = alfball; + return; + } + + + +} + + + +static float roll = 0.0; +#define MINe(p,q) ((p <= q) ? p : q) + +int reallyactive; + +void R_AddParticles (void) +{ + particle_t *p, *next; + float alpha; + float time, time2; + vec3_t oldorg; // leilei + particle_t *active, *tail; + vec3_t rotate_ang; + + float frametime; + float time3; + float time1; + float dvel; + float grav; + + float f; + + int intheworld = 0; + + if (!initparticles) + R_ClearParticles (); + + // This is supposed to prevent excessive calculations, but it's buggy and not working properly and conflicts + // with the hud, of all things + + + // leilei - quake time stuf + frametime = THEtime- oldTime; + frametime *= 0.001; + time3 = frametime * 15; + time2 = frametime * 10; // 15; + time1 = frametime * 5; + //grav = frametime * -800; + + grav = PARTICLE_GRAVITY; + dvel = 4*frametime; + + time = frametime; + + + VectorCopy( backEnd.refdef.viewaxis[0], pvforward ); + VectorCopy( backEnd.refdef.viewaxis[1], pvright ); + VectorCopy( backEnd.refdef.viewaxis[2], pvup ); + + vectoangles( backEnd.refdef.viewaxis[0], rotate_ang ); + roll += ((THEtime- oldTime) * 0.1) ; + rotate_ang[ROLL] += (roll*0.9); + AngleVectors ( rotate_ang, rforward, rright, rup); + + oldTime = THEtime; + + + active = NULL; + tail = NULL; + + // Intended to keep physics calculations under control, but it doens't work properly. :( + //if ((!backEnd.doneParticles) && !(tr.refdef.rdflags & RDF_NOWORLDMODEL)) + for (p=active_particles ; p ; p=next) + { + + next = p->next; + + + //time = (THEtime- p->time)*0.001; + + VectorCopy(p->org, oldorg); + + + + // if we're told to die, it's most likely a quake particle. + if (p->die) + { + int scal = 2.6f; + p->endtime = THEtime + (p->die); + p->die = 0; + p->height= scal; + p->width= scal; + p->endheight= scal; + p->endwidth= scal; + p->bounce = 0; + p->bubbleit = 0; + // ri.Printf( PRINT_ALL, "boung!"); + p->colortype = P_INDEXED; + p->alpha = 1; + p->qolor = p->color; + p->time = THEtime; + p->startfade = THEtime; + p->rendertype = LFXQUAKE; + p->accel[0] = p->accel[1] = p->accel[2] = 0; + p->pshader = alfball; + //p->qarticle = 1; + } + + + + if (p->rendertype != LFXQUAKE){ + p->vel[0] += p->accel[0]*frametime; + p->vel[1] += p->accel[1]*frametime; + p->vel[2] += p->accel[2]*frametime; + } + + + + else + { + + p->vel[0] += frametime; + p->vel[1] += frametime; + p->vel[2] += frametime; + + int i; + switch (p->type) + { + case pt_static: + break; + case pt_fire: + p->ramp += time1; + if (p->ramp >= 6) + p->die = -1; + else + p->color = ramp3[(int)p->ramp]; + p->vel[2] += grav; + break; + + case pt_explode: + p->ramp += time2; + if (p->ramp >=8) + p->die = -1; + else + p->color = ramp1[(int)p->ramp]; + for (i=0 ; i<3 ; i++) + p->vel[i] += p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_explode2: + p->ramp += time3; + if (p->ramp >=8) + p->die = -1; + else + p->color = ramp2[(int)p->ramp]; + for (i=0 ; i<3 ; i++) + p->vel[i] -= p->vel[i]*frametime; + p->vel[2] -= grav; + break; + + case pt_blob: + for (i=0 ; i<3 ; i++) + p->vel[i] += p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_blob2: + for (i=0 ; i<2 ; i++) + p->vel[i] -= p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_grav: + p->vel[2] -= grav * 20; + break; + + case pt_slowgrav: + p->accel[2] -= grav; + break; + } + + + + + if (THEtime> p->endtime) + { + p->next = free_particles; + free_particles = p; + p->type = 0; + p->color = 0; + p->alpha = 0; + p->qolor = 0; + p->accel[0] = 0; + p->accel[1] = 0; + p->accel[2] = 0; + p->rollvel = 0; + p->rollfriction = 0; + //p->qarticle = 0; + p->cols[0][0] = 0; + p->cols[1][0] = 0; + p->cols[2][0] = 0; + p->cols[3][0] = 0; + p->cols[0][1] = 0; + p->cols[1][1] = 0; + p->cols[2][1] = 0; + p->cols[3][1] = 0; + p->cols[0][2] = 0; + p->cols[1][2] = 0; + p->cols[2][2] = 0; + p->cols[3][2] = 0; + p->cols[0][3] = 0; + p->cols[1][3] = 0; + p->cols[2][3] = 0; + p->cols[3][3] = 0; + p->cols[0][4] = 0; + p->cols[1][4] = 0; + p->cols[2][4] = 0; + p->cols[3][4] = 0; + p->airfriction = 0; + p->bounce = 0; + p->bubbleit = 0; + p->material = 0; + p->active_trail = 0; + continue; + } + + } + oldorg[0] = p->org[0]; + oldorg[1] = p->org[1]; + oldorg[2] = p->org[2]; + + + + + + p->org[0] += p->vel[0]*frametime; + p->org[1] += p->vel[1]*frametime; + p->org[2] += p->vel[2]*frametime; + + if (p->rendertype != LFXQUAKE) + { + if (alpha > 1.0) + alpha = 1; + if (p->rollfriction){ + f = 1.0f - MINe(p->rollfriction * frametime, 1); + p->rollvel *= f; + } + + if (p->airfriction){ + f = 1.0f - MINe(p->airfriction * frametime, 1); + VectorScale(p->vel, f, p->vel); + } + + + p->roll += (p->rollvel*frametime); + + + + alpha = p->alpha + time*p->alphavel; + + // hack to prevent that one long particle from going crazy in the world. + if (p->startfade > THEtime){ + p->alpha = -1; // kill it + } + + if (alpha <= 0) + { // faded out + p->next = free_particles; + free_particles = p; + p->type = 0; + p->airfriction = 0; + p->color = 0; + p->alpha = 0; + p->endtime = THEtime- 0.1; + p->active_trail = 0; + continue; + } + + + if (THEtime> p->endtime || p->alpha < 0.0f) + { + p->next = free_particles; + free_particles = p; + p->type = 0; + p->color = 0; + p->alpha = 0; + p->qolor = 0; + p->accel[0] = 0; + p->accel[1] = 0; + p->accel[2] = 0; + p->rollvel = 0; + p->rollfriction = 0; + //p->qarticle = 0; + p->cols[0][0] = 0; + p->cols[1][0] = 0; + p->cols[2][0] = 0; + p->cols[3][0] = 0; + p->cols[0][1] = 0; + p->cols[1][1] = 0; + p->cols[2][1] = 0; + p->cols[3][1] = 0; + p->cols[0][2] = 0; + p->cols[1][2] = 0; + p->cols[2][2] = 0; + p->cols[3][2] = 0; + p->cols[0][3] = 0; + p->cols[1][3] = 0; + p->cols[2][3] = 0; + p->cols[3][3] = 0; + p->cols[0][4] = 0; + p->cols[1][4] = 0; + p->cols[2][4] = 0; + p->cols[3][4] = 0; + p->airfriction = 0; + p->bounce = 0; + p->bubbleit = 0; + p->material = 0; + p->active_trail = 0; + continue; + } + + + } + + + + + + + p->next = NULL; + if (!tail) + active = tail = p; + else + { + tail->next = p; + tail = p; + } + + + + // leilei - trail stuffs + + vectoangles( p->vel, p->angle ); + p->stretch = 34; + p->src[0] = p->org[0]; + p->src[1] = p->org[1]; + p->src[2] = p->org[2]; + + p->dest[0] = p->org[0] + p->vel[0] + p->accel[0]; + p->dest[1] = p->org[1] + p->vel[1] + p->accel[1]; + p->dest[2] = p->org[2] + p->vel[2] + p->accel[2]; + + + // leilei - bubble conversion + if(p->bubbleit && p->type != LFXBUBBLE) + { + int contents = CM_PointContents( p->org, 0 ); + if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME ) ) { + p->type = LFXBUBBLE; + p->pshader = watbubble; + p->airfriction = 2.0f; + p->accel[0] = 0; + p->accel[1] = 0; + p->accel[2] = 66; + p->cols[0][0] = 1; p->cols[0][1] = 1; p->cols[0][2] = 1; + p->cols[1][0] = 1; p->cols[1][1] = 1; p->cols[1][2] = 1; + p->cols[2][0] = 1; p->cols[2][1] = 1; p->cols[2][2] = 1; + p->cols[3][0] = 1; p->cols[3][1] = 1; p->cols[3][2] = 1; + p->endtime += 1000; // last it a wile + } + + } + if(p->type == LFXBUBBLE) + { + int contents = CM_PointContents( p->org, 0 ); + if ( contents | ( CONTENTS_WATER | CONTENTS_SLIME ) ) { + p->endtime = THEtime; + } + else + { + p->accel[0] = (crandom() * 4 - 2); + p->accel[1] = (crandom() * 4 - 2); + p->accel[2] = 66; + + } + + } + + + // leilei - bounce physics + if(p->bounce > 0) + { + trace_t trace; + float dist; + + // Do the trace of truth + P_Trace (&trace, oldorg, NULL, NULL, p->org, -1, CONTENTS_SOLID); + { + if (trace.fraction < 1){ + + VectorCopy(trace.endpos, p->org); // particle where we've hit from + + if (p->bounce < 0) + { + // bounce -1 means remove on impact + p->endtime = THEtime; + } + + // anything else - bounce off solid + dist = DotProduct(p->vel, trace.plane.normal) * -p->bounce; + VectorMA(p->vel, dist, trace.plane.normal, p->vel); + // lets roll + //p->vel[2] = 7; + if(p->bounce < 0.2f) + p->alpha = -5; // kill! + } + } + } + + //R_AddParticleToScene (p, p->org, alpha); + + + } + + active_particles = active; + + reallyactive = active; + + backEnd.doneParticles = qtrue; // we did it! +} + + +void R_RenderParticles (void) +{ + particle_t *p, *next; + float alpha; + float time, time2; + vec3_t oldorg; // leilei + particle_t *active, *tail; + vec3_t rotate_ang; + + float frametime; + float time3; + float time1; + float dvel; + float grav; + + float f; + + + if (!initparticles) + return; + + if (!backEnd.doneParticles) + R_AddParticles(); + + active_particles = reallyactive; + + for (p=active_particles ; p ; p=next) + { + next = p->next; + R_AddParticleToScene (p, p->org, p->alpha); + } + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// +// leilei's LFX particle system effects +// + + +void R_LFX_Blood (vec3_t org, vec3_t dir, float pressure) +{ + int i, j; + int count = pressure * 4; + particle_t *p; + + for (i = 0; i < count; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + p->time = THEtime; + p->bubbleit = 2; // dissolve + p->endtime = THEtime+ (1200 * (crandom() * 22)); + //p->startfade = p->endtime; + //p->color = GREY75; + p->rendertype = LFXSMOKE; + p->alpha = 1.0f; + p->alphavel = 2.0f; + p->height = 1.5; + p->width = 1.5; + p->endheight = 1.5; + p->endwidth = 1.5; + + p->cols[0][0] = p->cols[0][1] = p->cols[0][2] = p->cols[0][3] = p->cols[0][4] = 1.0; + p->cols[1][0] = p->cols[1][1] = p->cols[1][2] = p->cols[1][3] = p->cols[1][4] = 0.0; + p->cols[2][0] = p->cols[2][1] = p->cols[2][2] = p->cols[2][3] = p->cols[2][4] = 0.0; + + // Manage blending Functions + p->pshader = addsmoke; + + p->colortype = P_LFX; + + + VectorCopy(org, p->org); + p->bounce = 1.1f; + for (j = 0; j < 3; j++) { + //p->org[j] = org[j] + ((rand() & (count/8)) - (count/16)); + p->org[j] = org[j] + ((crandom() * (count/16)) - (count/32)); + p->vel[j] = dir[j] * (i * 2.6); + + p->vel[j] *= 0.01; + } + + p->accel[0] = p->accel[1] = p->accel[2] = 0; + p->accel[2] = -(PARTICLE_GRAVITY*8); + + p->airfriction = 0; + // p->org[j] = org[j] + (rand()&((count))-(count)); + // p->vel[j] = dir[j]*(rand()*(count*0.5))-(count) * 0.7; + // p->vel[2] += (i / 5); + + // } + + } + + +} + + +void R_LFX_Smoke (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc) +{ + int i, j; + int cont = 50; + particle_t *p; + + cont = (44 / (count / 2 + 1)) + 1; + + for (i = 0; i < cont; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + p->time = THEtime; + + p->endtime = THEtime+ duration; + p->startfade = THEtime; + + p->rendertype = LFXSMOKE; + p->alpha = 0.1f; + p->alphavel = 0.0f; + p->height = p->width = 1.0 * (count / 3); + p->bubbleit = 0; + p->endheight = p->height + scaleup; + p->endwidth = p->width + scaleup; + + + // Manage random roll and + p->rotate = qtrue; + p->roll = crandom()*179; + + p->cols[0][0] = color1[0]; + p->cols[1][0] = color1[1]; + p->cols[2][0] = color1[2]; + p->cols[3][0] = color1[3]; + + p->cols[0][1] = color2[0]; + p->cols[1][1] = color2[1]; + p->cols[2][1] = color2[2]; + p->cols[3][1] = color2[3]; + + p->cols[0][2] = color3[0]; + p->cols[1][2] = color3[1]; + p->cols[2][2] = color3[2]; + p->cols[3][2] = color3[3]; + + p->cols[0][3] = color4[0]; + p->cols[1][3] = color4[1]; + p->cols[2][3] = color4[2]; + p->cols[3][3] = color4[3]; + + p->cols[0][4] = color5[0]; + p->cols[1][4] = color5[1]; + p->cols[2][4] = color5[2]; + p->cols[3][4] = color5[3]; + + // Manage blending Functions + if (blendfunc == 1) + p->pshader = addsmoke; + else if (blendfunc == 2) + p->pshader = modsmoke; + else if (blendfunc == 3) + p->pshader = subsmoke; + else if (blendfunc == 8) + p->pshader = fireball; + else + p->pshader = alfsmoke; + + p->colortype = P_LFX; + + VectorCopy(org, p->org); + + // Manage spread of origin and velocity + for (j = 0; j < 3; j++) { + //p->org[j] = org[j] + ((crandom() * (spread / 8)) - (spread/16)); + p->org[j] = org[j]; + + p->vel[j] = (crandom() * dir[j]) * speed; + p->vel[j] += ((crandom() * (spread)) - (spread/2)); + } + + p->airfriction = 1.6f; + p->bounce = 1.7f; + p->rollvel = crandom() * 40 - 20; + p->rollfriction = 0.7; + } +} + + + + +void R_LFX_Smoke2 (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scale, float scaleup, int blendfunc) +{ + int i, j; + int cont = 50; + particle_t *p; + + cont = count; + + p = 0; // die warnings + + for (i = 0; i < cont; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + p->time = THEtime; + + p->endtime = THEtime+ duration; + p->startfade = THEtime; + p->bubbleit = 1; + p->rendertype = LFXSMOKE; + p->alpha = 0.1f; + p->alphavel = 0.0f; + p->height = p->width = (1.0 * scale); + + p->endheight = p->height + scaleup; + p->endwidth = p->width + scaleup; + + + // Manage random roll and + p->rotate = qtrue; + p->roll = crandom()*179; + + p->cols[0][0] = color1[0]; + p->cols[1][0] = color1[1]; + p->cols[2][0] = color1[2]; + p->cols[3][0] = color1[3]; + + p->cols[0][1] = color2[0]; + p->cols[1][1] = color2[1]; + p->cols[2][1] = color2[2]; + p->cols[3][1] = color2[3]; + + p->cols[0][2] = color3[0]; + p->cols[1][2] = color3[1]; + p->cols[2][2] = color3[2]; + p->cols[3][2] = color3[3]; + + p->cols[0][3] = color4[0]; + p->cols[1][3] = color4[1]; + p->cols[2][3] = color4[2]; + p->cols[3][3] = color4[3]; + + p->cols[0][4] = color5[0]; + p->cols[1][4] = color5[1]; + p->cols[2][4] = color5[2]; + p->cols[3][4] = color5[3]; + + + if (blendfunc == 1) + p->pshader = addsmoke; + else if (blendfunc == 2) + p->pshader = modsmoke; + else if (blendfunc == 3) + p->pshader = subsmoke; + else if (blendfunc == 8) + p->pshader = fireball; + else + p->pshader = alfsmoke; + + p->colortype = P_LFX; + + VectorCopy(org, p->org); +/* + // Manage spread of origin and velocity + for (j = 0; j < 3; j++) { + //p->org[j] = org[j] + ((crandom() * (spread / 8)) - (spread/16)); + p->org[j] = org[j]; + + p->vel[j] = (crandom() * dir[j]) * speed; + p->vel[j] += ((crandom() * (spread)) - (spread/2)); + } + + } +*/ + // Manage spread of origin and velocity + for (j = 0; j < 3; j++) { + p->org[j] = org[j]; + p->vel[j] = (rand() & (int)spread) - (int)(spread * 0.5f); + p->vel[j] += dir[j]; + p->vel[j] += (dir[j] * (rand() & (int)speed)); + + } + + //p->rollvel = crandom() * (50 - 100)*DotProduct(p->vel); + p->rollvel = crandom() * ((p->vel[0]+p->vel[1]+p->vel[2])/6) - ((p->vel[0]+p->vel[1]+p->vel[2])/3); + p->rollfriction = 2; + p->airfriction = 3.7f; + p->accel[2] = (PARTICLE_GRAVITY*1.3); + p->bounce = 3.5f; + + p->bounce = 0.0f; // bounce is slow... + } +} + + +void R_LFX_Shock (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc) +{ + int i, j; + particle_t *p; + + + for (i = 0; i < count; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + p->time = THEtime; + + p->endtime = THEtime+ duration; + p->startfade = THEtime; + p->bubbleit = 0; + p->rendertype = LFXSHOCK; + +// p->rendertype = BLOODRED; // note - not actually bloodred. + p->alpha = 0.1f; + p->alphavel = 0.0f; + //p->qolor = (color & ~7) + (rand() & 7); + p->height = p->width = 1.0 * (count / 3); + + p->endheight = p->height + scaleup; + p->endwidth = p->width + scaleup; + + + // Manage random roll and + p->rotate = qtrue; + //p->rotate = qtrue; + p->roll = crandom()*179; + //p->roll = rand()%179; + + p->dir[0] = dir[0]; + p->dir[1] = dir[1]; + p->dir[2] = dir[2]; + + p->cols[0][0] = color1[0]; + p->cols[1][0] = color1[1]; + p->cols[2][0] = color1[2]; + p->cols[3][0] = color1[3]; + + p->cols[0][1] = color2[0]; + p->cols[1][1] = color2[1]; + p->cols[2][1] = color2[2]; + p->cols[3][1] = color2[3]; + + p->cols[0][2] = color3[0]; + p->cols[1][2] = color3[1]; + p->cols[2][2] = color3[2]; + p->cols[3][2] = color3[3]; + + p->cols[0][3] = color4[0]; + p->cols[1][3] = color4[1]; + p->cols[2][3] = color4[2]; + p->cols[3][3] = color4[3]; + + p->cols[0][4] = color5[0]; + p->cols[1][4] = color5[1]; + p->cols[2][4] = color5[2]; + p->cols[3][4] = color5[3]; + + + // Manage blending Functions + if (blendfunc == 1) + p->pshader = addshock; + else if (blendfunc == 2) + p->pshader = modshock; + else if (blendfunc == 14) + p->pshader = watsplash; + else if (blendfunc == 3) + p->pshader = subshock; + else + + p->pshader = alfshock; + p->colortype = P_LFX; + + VectorCopy(org, p->org); + + // Manage spread of origin and velocity + for (j = 0; j < 3; j++) { + //p->org[j] = org[j] + ((crandom() * (spread / 8)) - (spread/16)); + p->org[j] = org[j]; + + p->vel[j] = (crandom() * dir[j]) * speed; + p->vel[j] += ((crandom() * (spread)) - (spread/2)); + } + + // Manage the Air Friction hack. + + + // for (j = 0; j < 3; j++) { + // p->accel[j] = (p->vel[j] * -1); + // } + + + + + //p->accel[0] = p->accel[1] = p->accel[2] = 0; + //p->accel[2] = -(PARTICLE_GRAVITY / 2); + + p->airfriction = 0; + } +} + + +void R_LFX_Spark (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc) +{ + int i, j; + int cont = 50; + particle_t *p; + + cont = count; + + for (i = 0; i < cont; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + p->time = THEtime; + + p->endtime = THEtime+ duration; + p->startfade = THEtime; + + p->rendertype = LFXSPARK; + //p->color = EMISIVEFADE; + p->alpha = 1.0f; + p->alphavel = 0.0f; + //p->qolor = (color & ~7) + (rand() & 7); + p->height = p->width = scaleup; + + p->endheight = p->height; + p->endwidth = p->width; + + + p->rotate = qfalse; // sparks don't rotate + p->roll = 0; // sparks don't roll + + + p->accel[0] = p->accel[1] = p->accel[2] = 0; + + p->bubbleit = 1; + + p->cols[0][0] = color1[0]; + p->cols[1][0] = color1[1]; + p->cols[2][0] = color1[2]; + p->cols[3][0] = color1[3]; + + p->cols[0][1] = color2[0]; + p->cols[1][1] = color2[1]; + p->cols[2][1] = color2[2]; + p->cols[3][1] = color2[3]; + + p->cols[0][2] = color3[0]; + p->cols[1][2] = color3[1]; + p->cols[2][2] = color3[2]; + p->cols[3][2] = color3[3]; + + p->cols[0][3] = color4[0]; + p->cols[1][3] = color4[1]; + p->cols[2][3] = color4[2]; + p->cols[3][3] = color4[3]; + + p->cols[0][4] = color5[0]; + p->cols[1][4] = color5[1]; + p->cols[2][4] = color5[2]; + p->cols[3][4] = color5[3]; + + // Manage blending Functions + if (blendfunc == 1) + p->pshader = addball; + else if (blendfunc == 2) + p->pshader = modball; + else if (blendfunc == 3) + p->pshader = subball; + else if (blendfunc == 666) + p->pshader = blood1; + else + p->pshader = alfball; + + + + //p->pshader = cgs.media.whiteShader; +// + + p->colortype = P_LFX; + + VectorCopy(org, p->org); + + + // Manage spread of origin and velocity + for (j = 0; j < 3; j++) { + p->org[j] = org[j]; + p->vel[j] = (rand() & (int)spread) - (int)(spread * 0.5f); + p->vel[j] += dir[j]; + p->vel[j] += (dir[j] * (rand() & (int)speed)); + + } + +/* + for (j = 0; j < 3; j++) { + float sped = speed * (1 + crandom()) + (speed * 0.3f); + //p->org[j] = org[j] + ((crandom() * (spread / 8)) - (spread/16)); + p->org[j] = org[j]; + + p->vel[j] = (dir[j]) * sped; + p->vel[j] += ((crandom() * (spread)) - (spread/2)); + + // p->vel[j] *= crandom(); + + + } +*/ + // a little kick up + p->vel[2] += (speed * 0.4f); + + + + p->accel[0] = p->accel[1] = p->accel[2] = 0; + p->accel[2] = -(800 * 0.5f); // TODO: insert proper gravity. + + // prepare the initial stretch frame + + p->airfriction = 1.6f; + p->bounce = 1.6f; + if (blendfunc == 666){ + p->bounce = 666; // instantly make a red decal and kill itself. for blood + p->accel[2] = -(800); // TODO: insert proper gravity. + } + } +// VectorCopy(p->org,p->torg[0]); // a org to stretch from. + +} + + + + +void R_LFX_Burst (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc) +{ + int i, j; + int cont = 50; + particle_t *p; + + cont = count; + + for (i = 0; i < cont; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + + p->time = THEtime; + + p->endtime = THEtime+ duration; + p->startfade = THEtime; + + p->rendertype = LFXBURST; + //p->color = EMISIVEFADE; + p->alpha = 1.0f; + p->alphavel = 0.0f; + //p->qolor = (color & ~7) + (rand() & 7); + p->height = p->width = scaleup; + + p->endheight = p->height; + p->endwidth = p->width; + + + p->rotate = qfalse; // sparks don't rotate + p->roll = 0; // sparks don't roll + + + p->accel[0] = p->accel[1] = p->accel[2] = 0; + + p->cols[0][0] = color1[0]; + p->cols[1][0] = color1[1]; + p->cols[2][0] = color1[2]; + p->cols[3][0] = color1[3]; + + p->cols[0][1] = color2[0]; + p->cols[1][1] = color2[1]; + p->cols[2][1] = color2[2]; + p->cols[3][1] = color2[3]; + + p->cols[0][2] = color3[0]; + p->cols[1][2] = color3[1]; + p->cols[2][2] = color3[2]; + p->cols[3][2] = color3[3]; + + p->cols[0][3] = color4[0]; + p->cols[1][3] = color4[1]; + p->cols[2][3] = color4[2]; + p->cols[3][3] = color4[3]; + + p->cols[0][4] = color5[0]; + p->cols[1][4] = color5[1]; + p->cols[2][4] = color5[2]; + p->cols[3][4] = color5[3]; + + // Manage blending Functions + if (blendfunc == 1) + p->pshader = addball; + else if (blendfunc == 2) + p->pshader = modball; + else if (blendfunc == 3) + p->pshader = subball; + else if (blendfunc == 7) + p->pshader = watburst; + else if (blendfunc == 666) + p->pshader = blood2; + else + p->pshader = alfball; + + + + p->colortype = P_LFX; + + VectorCopy(org, p->org); + + + // Manage spread of origin and velocity + for (j = 0; j < 3; j++) { + float sped = speed * (1 + crandom()) + (speed * 0.3f); + p->vel[j] = ((crandom() * (spread)) - (spread/2)) / 360; + p->vel[j] *= sped; + + } + + p->accel[0] = p->accel[1] = p->accel[2] = 0; + + // prepare the initial stretch frame + + p->airfriction = 1.6f; + //p->bounce = 2.0f; + VectorCopy(p->org,p->torg[0]); // a org to stretch from. + + if (blendfunc == 666){ + p->airfriction = 2.9f; + // p->bounce = 1.3f; + p->accel[2] = -(PARTICLE_GRAVITY/2); + + } + // for water splashes + if (blendfunc == 7){ + p->airfriction = 1.8f; + p->bounce = 0.0f; + p->vel[0] = dir[0]; + p->vel[1] = dir[1]; + p->vel[2] = dir[2]; + p->height = 2; + p->width = 2; + p->endheight = 8; + p->endwidth = 8; + p->accel[2] = -(PARTICLE_GRAVITY); + + } + + } +} + + +// i'll probably fail, but still. GENERIC FUNCTION +void R_LFX_Generic (int type, vec3_t org, vec3_t dir, float alpha, int spread, int orgoff, float randroll, float speed, int cred, int cgreen, int cblue, int count, int duration, float scale, float scaleup, float bounce, float airfriction, float grav, float rollfriction, shader_t *shader) +{ + int i, j; + int cont = 50; + particle_t *p; + + cont = count; + + p = 0; // die warnings + + for (i = 0; i < cont; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + p->time = THEtime; + p->endtime = THEtime+ duration; + p->startfade = THEtime; + p->bubbleit = 0; // don't do bubble check for any generic particles. + p->rendertype = type; + p->alpha = alpha; + p->alphavel = 0.0f; + p->height = p->width = (1.0 * scale); + + p->endheight = p->height + scaleup; + p->endwidth = p->width + scaleup; + + p->rotate = qtrue; + p->roll = 0;//crandom()*randroll; + + + // we only use one color for this fine generic function + + p->cols[0][0] = cred / 255; + p->cols[1][0] = cgreen / 255; + p->cols[2][0] = cblue / 255; + p->cols[3][0] = 1.0f; + + p->cols[0][1] = cred / 255; + p->cols[1][1] = cgreen / 255; + p->cols[2][1] = cblue / 255; + p->cols[3][1] = 1.0f; + + p->cols[0][2] = cred / 255; + p->cols[1][2] = cgreen / 255; + p->cols[2][2] = cblue / 255; + p->cols[3][2] = 1.0f; + + p->cols[0][3] = cred / 255; + p->cols[1][3] = cgreen / 255; + p->cols[2][3] = cblue / 255; + p->cols[3][3] = 1.0f; + + p->cols[0][4] = cred / 255; + p->cols[1][4] = cgreen / 255; + p->cols[2][4] = cblue / 255; + p->cols[3][4] = 1.0f; + + + p->pshader = shader; + + //p->rollvel = crandom() * (50 - 100)*DotProduct(p->vel); + p->rollvel = crandom() * ((p->vel[0]+p->vel[1]+p->vel[2])/6) - ((p->vel[0]+p->vel[1]+p->vel[2])/3); + p->rollfriction = rollfriction; + p->airfriction = airfriction; + p->accel[0] = p->accel[1] = 0; + p->accel[2] = (PARTICLE_GRAVITY*grav); + p->bounce = bounce; + + + p->colortype = P_LFXSIMPLE; // it's always an lfx for this one. + + VectorCopy(org, p->org); + + // Manage spread of origin and velocity + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand() % orgoff) - (int)(orgoff * 0.5f)); + //p->org[j] = org[j]; + p->vel[j] = (rand() & (int)spread) - (int)(spread * 0.5f); + p->vel[j] += dir[j]; + p->vel[j] += (dir[j] * (rand() & (int)speed)); + + } + } +} + + + + + + + + + + + +// macros kind of + + + + +// give some turbulence to smokes +void R_LFX_PushSmoke (vec3_t there, float force) +{ + // will reimplement properly later +} + + + + +void R_LetsBounce ( particle_t *p) +{ + + // will reimplement properly later + +} + + + + + + + + + + + + + +// QUAKE EFFECTS + + +// attempt at generic particles function similar to quake... +void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) +{ + int i, j; + particle_t *p; + + for (i = 0; i < count; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + p->die = cl.time + 0.1*(rand()%5); + p->color = (color&~7) + (rand()&7); + p->type = pt_slowgrav; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()&15)-8); + p->vel[j] = dir[j]*15;// + (rand()%300)-150; + } + } +} + + +// also from Quake! + +void R_QarticleExplosion(vec3_t org) +{ + int i, j; + particle_t *p; + + for (i = 0; i < 512; i++) { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->rendertype = EMISIVEFADE; + p->alpha = 1.0f; + p->alphavel = 1.0f; + p->time = THEtime; + + p->bubbleit = 0; + // crap for q3's particle system... + p->endtime = THEtime+ 500; + p->startfade = p->endtime; + p->height = 0.5; + p->width = 0.5; + p->endheight = 0.5; + p->endwidth = 0.5; + p->pshader = alfsmoke; + p->qolor = ramp1[0]; + +// p->qolor = 44; + + VectorCopy(org, p->org); + + p->ramp = rand() & 3; + if (i & 1) { +// p->type = P_QUAKE; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand() % 32) - 16); + p->vel[j] = (rand() % 512) - 256; + p->accel[j] = p->vel[j] * 4; + } + } else { +// p->type = P_QUAKE; + for (j = 0; j < 3; j++) { + p->org[j] = org[j] + ((rand() % 32) - 16); + p->vel[j] = (rand() % 512) - 256; + p->accel[j] = p->vel[j] * 4; + } + } + } +} + + +void Q_ParticleExplosion (vec3_t org) +{ + int i, j; + particle_t *p; + + for (i=0 ; i<1024 ; i++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 5; + p->color = ramp1[0]; + p->ramp = rand()&3; + if (i & 1) + { + p->type = pt_explode; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } + else + { + p->type = pt_explode2; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } + } +} + +void Q_RocketTrail (vec3_t start, vec3_t end, int type) +{ + vec3_t vec; + float len; + int j; + particle_t *p; + int dec; + static int tracercount; + + VectorSubtract (end, start, vec); + len = VectorNormalize (vec); + if (type < 128) + dec = 3; + else + { + dec = 1; + type -= 128; + } + + while (len > 0) + { + len -= dec; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + VectorCopy (vec3_origin, p->vel); + p->die = cl.time + 2; + + switch (type) + { + case 0: // rocket trail + p->ramp = (rand()&3); + p->qolor = ramp3[(int)p->ramp]; + p->type = pt_fire; + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 1: // smoke smoke + p->ramp = (rand()&3) + 2; + p->color = ramp3[(int)p->ramp]; + p->type = pt_fire; + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 2: // blood + p->type = pt_grav; + p->color = 67 + (rand()&3); + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 3: + case 5: // tracer + p->die = cl.time + 0.5; + p->type = pt_static; + if (type == 3) + p->color = 52 + ((tracercount&4)<<1); + else + p->color = 230 + ((tracercount&4)<<1); + + tracercount++; + + VectorCopy (start, p->org); + if (tracercount & 1) + { + p->vel[0] = 30*vec[1]; + p->vel[1] = 30*-vec[0]; + } + else + { + p->vel[0] = 30*-vec[1]; + p->vel[1] = 30*vec[0]; + } + break; + + case 4: // slight blood + p->type = pt_grav; + p->color = 67 + (rand()&3); + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + len -= 3; + break; + + case 6: // voor trail + p->color = 9*16 + 8 + (rand()&3); + p->type = pt_static; + p->die = cl.time + 0.3; + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()&15)-8); + break; + } + + + VectorAdd (start, vec, start); + } +} + + +void LFX_ShaderInit ( void ) +{ + + addsmoke = R_FindShader( "psmoke-add", LIGHTMAP_NONE, qtrue ); + subsmoke = R_FindShader( "psmoke-sub", LIGHTMAP_NONE, qtrue ); + modsmoke = R_FindShader( "psmoke-mod", LIGHTMAP_NONE, qtrue ); + alfsmoke = R_FindShader( "psmoke-blend", LIGHTMAP_NONE, qtrue ); + + blood1 = R_FindShader( "pblood1", LIGHTMAP_NONE, qtrue ); + blood2 = R_FindShader( "pblood1", LIGHTMAP_NONE, qtrue ); + + watsplash = R_FindShader( "pwatersplash", LIGHTMAP_NONE, qtrue ); + watburst = R_FindShader( "pwaterburst", LIGHTMAP_NONE, qtrue ); + watbubble = R_FindShader( "pwaterbubble", LIGHTMAP_NONE, qtrue ); + fireball = R_FindShader( "pfireball", LIGHTMAP_NONE, qtrue ); + + addball = R_FindShader( "pball-add", LIGHTMAP_NONE, qtrue ); + subball = R_FindShader( "pball-sub", LIGHTMAP_NONE, qtrue ); + modball = R_FindShader( "pball-mod", LIGHTMAP_NONE, qtrue ); + alfball = R_FindShader( "pball-blend", LIGHTMAP_NONE, qtrue ); + + + addshock = R_FindShader( "pshock-add", LIGHTMAP_NONE, qtrue ); + subshock = R_FindShader( "pshock-sub", LIGHTMAP_NONE, qtrue ); + modshock = R_FindShader( "pshock-mod", LIGHTMAP_NONE, qtrue ); + alfshock = R_FindShader( "pshock-blend", LIGHTMAP_NONE, qtrue ); + + R_ClearParticles (); +} + +// 1996 - it's like the first game ok +// - just dots + +void LFX_ParticleEffect1996 (int effect, vec3_t org, vec3_t dir) +{ + vec3_t notatall; + + // Smoke trails on grenades and rockets + if (effect == 1) + { + R_RunParticleEffect (org, notatall, 10, 8); + //Q_RocketTrail(org, dir, r_leidebug->integer); + } + + // Bullet Hit + if (effect == 2 || effect == 3) + { + R_RunParticleEffect (org, notatall, 6, 20); + + } + + // Grenade/Rocket/Prox Explosion + + else if (effect == 5 || effect == 4 || effect == 11) + { + Q_ParticleExplosion(org); + + } + + // Blood Sprays for bullets + if (effect == 14) + { + R_RunParticleEffect (org, dir,21, 20); + } + + + // Water Splash for bullets + if (effect == 19) + { + R_RunParticleEffect (org, dir,41, 20); + } + + +} + + +// 200X - most games of that decade... +// - usually ltos of particles +// - usually +void LFX_ParticleEffect200X (int effect, vec3_t org, vec3_t dir) +{ + vec3_t origin, sprOrg, sprVel; // laziness + vec4_t colory, colory2, colory3, colory4; + + VectorCopy(org, sprOrg); + VectorCopy(org, origin); + VectorCopy(dir, sprVel); + + // Smoke trails on grenades and rockets + if (effect == 1) + { + colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 1.0; + colory2[0] = 0.5; colory2[1] = 0.5; colory2[2] = 0.5; colory2[3] = 0.8; + colory3[0] = 0.5; colory3[1] = 0.4; colory3[2] = 0.3; colory3[3] = 0.5; + colory4[0] = 0.5; colory4[1] = 0.4; colory4[2] = 0.3; colory4[3] = 0.0; + R_LFX_Smoke2 (sprOrg, sprVel, 1 + (random()*3), 0.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 2470, 4, 8+ (random()*6), 4); + } + + // Bullet Hit + if (effect == 2) + { + colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0; + colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8; + colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0; + + VectorMA( origin, 4, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + // Sparks + colory[0] = 1; colory[1] = 1; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 1; colory2[1] = 1; colory2[2] = 0.8; colory2[3] = 0.9; + colory3[0] = 0.7; colory3[1] = 0.5; colory3[2] = 0.2; colory3[3] = 0.7; + colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0; + + R_LFX_Burst (sprOrg, sprVel, 8366, 2, colory, colory2, colory3, colory4, colory4, 4, 50, 2, 1); + + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + R_LFX_Spark (sprOrg, sprVel, 95, 325, colory, colory2, colory3, colory4, colory4, 5, 140, 0.5f, 1); + R_LFX_Spark (sprOrg, sprVel, 95, 85, colory, colory2, colory3, colory4, colory4, 1, 1540, 0.5f, 1); + + //R_LFX_PushSmoke (sprOrg, 44); + + + } + + // Shotgun Hit + if (effect == 3) + { + colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0; + colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8; + colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0; + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 7, sprVel ); + R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0); + R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4); + colory[0] = 0.9; colory[1] = 0.8; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 0.7; colory2[1] = 0.5; colory2[2] = 0.2; colory2[3] = 0.9; + colory3[0] = 0.1; colory3[1] = 0.1; colory3[2] = 0.1; colory3[3] = 0.7; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + VectorMA( origin, 4, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + R_LFX_Shock (origin, dir, 0, 32, colory, colory2, colory3, colory4, colory4, 1, 200, 50,1); + colory[0] = 1; colory[1] = 1; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 1; colory2[1] = 1; colory2[2] = 0.8; colory2[3] = 0.9; + colory3[0] = 0.7; colory3[1] = 0.5; colory3[2] = 0.2; colory3[3] = 0.7; + colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0; + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + R_LFX_Spark (sprOrg, sprVel, 25, 85, colory, colory2, colory3, colory4, colory4, 3, 2540, 0.5f, 1); + } + + // Plasma Hit + if (effect == 6) + { + colory[0] = 1.0; colory[1] = 0.7; colory[2] = 1.0; colory[3] = 0.0; + colory2[0] = 0.3; colory2[1] = 0.7; colory2[2] = 1.0; colory2[3] = 0.5; + colory3[0] = 0.1; colory3[1] = 0.2; colory3[2] = 0.6; colory3[3] = 0.8; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 7, sprVel ); + R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0); + VectorMA( origin, 2, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + R_LFX_Shock (sprOrg, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1,600, 80,1); + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + R_LFX_Spark (sprOrg, sprVel, 25, 85, colory, colory2, colory3, colory4, colory4, 5, 5540, 0.5f, 1); + } + + // Lightning Hit + if (effect == 8) + { + colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0; + colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8; + colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0; + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 7, sprVel ); + R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4); + } + + + // Grenade/Rocket/Prox Explosion + + else if (effect == 5 || effect == 4 || effect == 11) + { + + + colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 1.0; colory2[1] = 1.0; colory2[2] = 0.5; colory2[3] = 0.9; + colory3[0] = 0.7; colory3[1] = 0.3; colory3[2] = 0.1; colory3[3] = 0.7; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + VectorMA( origin, 4, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + + R_LFX_Shock (sprOrg, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 500, 270, 1); + + // fireball + + colory[0] = 1.0; colory[1] = 0.2; colory[2] = 0.1; colory[3] = 0.0; + colory2[0] = 0.5; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.2; + colory3[0] = 0.1; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.7; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + VectorMA( origin, 12, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + + R_LFX_Smoke (sprOrg, sprVel, 32, 3.54, colory, colory2, colory3, colory4, colory4, 16, 1000, 94, 1); + + colory[0] = 1.0; colory[1] = 1.0; colory[2] = 0.9; colory[3] = 1.0; + colory2[0] = 1.0; colory2[1] = 0.7; colory2[2] = 0.2; colory2[3] = 0.9; + colory3[0] = 0.3; colory3[1] = 0.2; colory3[2] = 0.1; colory3[3] = 0.7; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + + R_LFX_Smoke (sprOrg, sprVel, 62, 2, colory, colory2, colory3, colory4, colory4, 12, 200,84, 8); + R_LFX_Smoke (sprOrg, sprVel, 32, 1.54, colory, colory2, colory3, colory4, colory4, 22, 600, 74, 8); + + R_LFX_Smoke (sprOrg, sprVel, 44, 1.3, colory, colory2, colory3, colory4, colory4, 3, 800,3, 8); + + R_LFX_Smoke (sprOrg, sprVel, 32, 0.54, colory, colory2, colory3, colory4, colory4, 12, 600, 74, 8); + + // Shroom Cloud + VectorMA( origin, 16, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + + colory[0] = 0.5; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 0.0; + colory2[0] = 1.0; colory2[1] = 1.0; colory2[2] = 0.2; colory2[3] = 0.2; + colory3[0] = 0.5; colory3[1] = 0.1; colory3[2] = 0.0; colory3[3] = 0.5; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + R_LFX_Smoke (sprOrg, sprVel, 3, 0.7, colory, colory2, colory3, colory4, colory4, 22, 300,135, 8); + + // Sparks! + + colory[0] = 1; colory[1] = 1; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 1; colory2[1] = 1; colory2[2] = 0.8; colory2[3] = 0.9; + colory3[0] = 0.7; colory3[1] = 0.5; colory3[2] = 0.2; colory3[3] = 0.7; + colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0; + VectorMA( origin, 12, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + + R_LFX_Burst (sprOrg, sprVel, 175, 15, colory, colory2, colory3, colory4, colory4, 15, 240, 22, 1); + + R_LFX_Spark (sprOrg, sprVel, 175, 5, colory, colory2, colory3, colory4, colory4, 25, 1240, 0.8f, 1); + + } + + // BFG + else if (effect == 9) + { + + + colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 0.3; colory2[1] = 1.0; colory2[2] = 0.2; colory2[3] = 0.9; + colory3[0] = 0.0; colory3[1] = 0.3; colory3[2] = 0.1; colory3[3] = 0.7; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + VectorMA( origin, 4, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + + R_LFX_Shock (sprOrg, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 300, 470, 1); + + // fireball + + + VectorMA( origin, 12, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + + R_LFX_Smoke (sprOrg, sprVel, 32, 3.54, colory, colory2, colory3, colory4, colory4, 16, 200, 174, 1); + + + R_LFX_Smoke (sprOrg, sprVel, 62, 2, colory, colory2, colory3, colory4, colory4, 12, 800,84, 8); + R_LFX_Smoke (sprOrg, sprVel, 32, 1.54, colory, colory2, colory3, colory4, colory4, 22, 400, 74, 8); + + R_LFX_Smoke (sprOrg, sprVel, 44, 1.3, colory, colory2, colory3, colory4, colory4, 3, 500,3, 8); + + R_LFX_Smoke (sprOrg, sprVel, 32, 0.54, colory, colory2, colory3, colory4, colory4, 12, 400, 74, 8); + + // Shroom Cloud + VectorMA( origin, 16, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + + R_LFX_Smoke (sprOrg, sprVel, 3, 0.7, colory, colory2, colory3, colory4, colory4, 22, 300,135, 8); + + // Sparks! + + VectorMA( origin, 12, dir, sprOrg ); + VectorScale( dir, 64, sprVel ); + + R_LFX_Burst (sprOrg, sprVel, 175, 15, colory, colory2, colory3, colory4, colory4, 15, 140, 32, 1); + + R_LFX_Spark (sprOrg, sprVel, 175, 5, colory, colory2, colory3, colory4, colory4, 15, 1040, 0.8f, 1); + + } + + // Nail Hit + if (effect == 10) + { + colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0; + colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8; + colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0; + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 7, sprVel ); + R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4); + + colory[0] = 0.7; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 0.0; + colory2[0] = 0.3; colory2[1] = 0.7; colory2[2] = 1.0; colory2[3] = 0.5; + colory3[0] = 0.0; colory3[1] = 0.2; colory3[2] = 0.5; colory3[3] = 0.8; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + + VectorMA( origin, 4, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + + R_LFX_Burst (sprOrg, sprVel, 8366, 2, colory, colory2, colory3, colory4, colory4, 4, 150, 3, 1); + + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + + R_LFX_Spark (sprOrg, sprVel, 95, 225, colory, colory2, colory3, colory4, colory4, 5, 140, 0.5f, 1); + R_LFX_Spark (sprOrg, sprVel, 95, 185, colory, colory2, colory3, colory4, colory4, 1, 2540, 0.5f, 1); + + + } + + // Blood Sprays for bullets + if (effect == 14 && com_blood->integer) + { + sprVel[2] += 54; + colory[0] = 1.0; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 1.0; + colory2[0] = 0.8; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.8; + colory4[0] = 0.3; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + //R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0); + //R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4); + R_LFX_Burst (sprOrg, sprVel, 175, 15, colory, colory2, colory3, colory4, colory4, 2, 1755, 12, 666); + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 2, sprVel ); + //R_LFX_Spark (sprOrg, sprVel, 25, 85, colory, colory2, colory3, colory4, colory4, 8, 2386, 0.5f, 666); + } + + // "Blood" Sprays for bullets + if (effect == 14 && !com_blood->integer) + { + + // nonviolent blue center + colory[0] = 0.0; colory[1] = 0.7; colory[2] = 1.0; colory[3] = 0.0; + colory2[0] = 0.0; colory2[1] = 0.0; colory2[2] = 1.0; colory2[3] = 0.5; + colory3[0] = 0.0; colory3[1] = 0.0; colory3[2] = 0.6; colory3[3] = 0.8; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + R_LFX_Burst (sprOrg, sprVel, 175, 15, colory, colory2, colory3, colory4, colory4, 2, 105, 12, 1); + R_LFX_Smoke (sprOrg, sprVel, 0, 0, colory, colory2, colory3, colory4, colory4, 32, 400, -33, 1); + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + + colory[0] = 1; colory[1] = 1; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 1; colory2[1] = 1; colory2[2] = 0.8; colory2[3] = 0.9; + colory3[0] = 0.7; colory3[1] = 0.5; colory3[2] = 0.2; colory3[3] = 0.7; + colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0; + + R_LFX_Spark (sprOrg, sprVel, 25, 85, colory, colory2, colory3, colory4, colory4, 2,586, 0.5f, 1); + R_LFX_Shock (origin, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 255, 39,1); + } + + + // Blood Spray for a gibbing + if (effect == 16 && com_blood->integer) + { + sprVel[2] += 124; + colory[0] = 1.0; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 1.0; + colory2[0] = 0.8; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.8; + colory4[0] = 0.3; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + // R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0); + // R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4); + R_LFX_Burst (sprOrg, sprVel, 275, 4, colory, colory2, colory3, colory4, colory4, 9, 1455, 42, 666); + } + + // Water Splash for bullets + if (effect == 19) + { + colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 0.3; colory2[1] = 0.5; colory2[2] = 0.6; colory2[3] = 0.6; + colory3[0] = 0.1; colory3[1] = 0.2; colory3[2] = 0.3; colory3[3] = 0.3; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + VectorScale( dir, 39, sprVel ); + R_LFX_Shock (origin, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 800, 80,14); + R_LFX_Burst (sprOrg, sprVel, 22, 266, colory, colory2, colory3, colory4, colory4, 1, 1900, 5, 7); + R_LFX_Spark (sprOrg, sprVel, 134, 4, colory, colory2, colory3, colory4, colory4, 7, 1286, 0.5f, 1); + } +/* + // these are not properly implemented through cgame yet as they call *every* frame instead of being a truly one shot effect. + // muzzieflash plasmagun + if (effect == 66) + { + colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 0.3; colory2[1] = 0.5; colory2[2] = 0.6; colory2[3] = 0.5; + colory3[0] = 0.1; colory3[1] = 0.2; colory3[2] = 0.3; colory3[3] = 0.8; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + VectorScale( dir, 39, sprVel ); + R_LFX_Shock (origin, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 255, 8,1); + //R_LFX_Burst (sprOrg, sprVel, 22, 266, colory, colory2, colory3, colory4, colory4, 1, 144, 2, 7); + //R_LFX_Spark (sprOrg, sprVel, 134, 4, colory, colory2, colory3, colory4, colory4, 7, 1556, 0.25f, 1); + } + // muzzleflash shotgun + if (effect == 63) + { + colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0; + colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8; + colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0; + + //R_LFX_Burst (sprOrg, sprVel, 22, 266, colory, colory2, colory3, colory4, colory4, 1, 144, 2, 7); + + R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*55.7), colory, colory2, colory3, colory4, colory4, 4, 300 + (random()*3000), 2, 8+ (random()*6), 4); + VectorScale( dir, 39, sprVel ); + R_LFX_Spark (sprOrg, sprVel, 14, 8, colory, colory2, colory3, colory4, colory4, 22, 556, 0.25f, 1); + } + +*/ +} + +// 1997 - +// - alpha blends ONLY! +// - low amounts of polygons +// - high atlas usage +void LFX_ParticleEffect1997 (int effect, vec3_t org, vec3_t dir) +{ + vec3_t origin, sprOrg, sprVel; // laziness + vec4_t colory, colory2, colory3, colory4; + + VectorCopy(org, sprOrg); + VectorCopy(org, origin); + VectorCopy(dir, sprVel); + + // Smoke trails on grenades and rockets + // this should be several smoke atlases along a line. + if (effect == 1) + { + + } + + // Bullet Hit + // a smoke puff, a badly looping spark model, and an occasional ball spark (no stretch) of a random amount from 1 to 6 balls. + if (effect == 2) + { + + } + + // Shotgun Hit + // can be just smoke puffs, preferably atlasy. + if (effect == 3) + { + + } + + // Plasma Hit + // should become a plain sprite atlas animation. + if (effect == 6) + { + + } + + // Lightning Hit + // can become a plain sprite, but we already have that, so..... + if (effect == 8) + { + + } + + + // Grenade/Rocket/Prox Explosion + // should be an explosion atlas, but on later versions there's several more delayed explosion atlases to spice up the variety + else if (effect == 5 || effect == 4 || effect == 11) + { + + + } + + // BFG, could be an expanding sphere with an explosion atlas + else if (effect == 9) + { + + + } + + // Blood Sprays for bullets + + if (effect == 14 && com_blood->integer) + { + colory[0] = 1.0; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 1.0; + colory2[0] = 0.8; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.8; + colory4[0] = 0.3; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + //R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0); + //R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4); + } + + // "Blood" Sprays for bullets + if (effect == 14 && !com_blood->integer) + { + // usually there are none. + } + + + // Blood Spray for a gibbing + if (effect == 16 && com_blood->integer) + { + // usually there are none. + } + + // Water Splash for bullets - a splash atlas burst animation. + if (effect == 19) + { + + } + +} + + +// 1998 - a certain game from washington state +// - some atlas animation, but not much +// - glquake particles are still present +// - alpha and additives only +// - sparks, but sparsely and no collision +// - some flare testing on some effects + +void LFX_ParticleEffect1998 (int effect, vec3_t org, vec3_t dir) +{ + vec3_t origin, sprOrg, sprVel; // laziness + vec4_t colory, colory2, colory3, colory4; + + VectorCopy(org, sprOrg); + VectorCopy(org, origin); + VectorCopy(dir, sprVel); + + // Smoke trails on grenades and rockets + // might be a beam. + if (effect == 1) + { + + } + + // Bullet Hit + // glquake black particles of debris coming off + // followed by a few stretchy sparks of orange that fall out of it + // + + + if (effect == 2) + { + // Sparks + colory[0] = 0.6; colory[1] = 0.4; colory[2] = 0.0; colory[3] = 1.0; + colory2[0] = 0.7; colory2[1] = 0.4; colory2[2] = 0.0; colory2[3] = 0.9; + colory3[0] = 0.5; colory3[1] = 0.2; colory3[2] = 0.0; colory3[3] = 0.7; + colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0; + + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + sprVel[2] += 2; + R_LFX_Spark (sprOrg, sprVel, 11, 32, colory, colory2, colory3, colory4, colory4, 4, 440, 0.5f, 1); + sprVel[2] += 64; + R_LFX_Generic + (LFXSMOKE, // Particle Type + sprOrg, // Origin + sprVel, // Velocity + 1.0f, // Starting Alpha + 85, // Spread Factor + 3, // Random Origin Offset + 0, // Random Roll Value + 0, // Additional Random Speed + 8, // Particle Color Red + 8, // Particle Color Green + 8, // Particle Color Blue + 8, // Particle Count + 400, // Particle Life + 0.5f, // Particle Scale + 0.5f, // Particle Scale Towards + 0.1f, // Particle Bounce Factor + 0, // Air Friction (stopping particle velocity in air) + -16.0f, // Particle Gravity Factor + 0.0f, // Particle Rolling Friction + alfball // Particle Shader + ); + } + + + else if (effect == 3) + { + if (rand() < 0.5f){ // only happens for half the pellets + // Sparks + colory[0] = 0.6; colory[1] = 0.4; colory[2] = 0.0; colory[3] = 1.0; + colory2[0] = 0.7; colory2[1] = 0.4; colory2[2] = 0.0; colory2[3] = 0.9; + colory3[0] = 0.5; colory3[1] = 0.2; colory3[2] = 0.0; colory3[3] = 0.7; + colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0; + + VectorMA( origin, 1, dir, sprOrg ); + VectorScale( dir, 1, sprVel ); + + R_LFX_Spark (sprOrg, sprVel, 95, 32, colory, colory2, colory3, colory4, colory4, 3, 440, 0.5f, 1); + sprVel[2] += 64; + R_LFX_Generic + (LFXSMOKE, // Particle Type + sprOrg, // Origin + sprVel, // Velocity + 1.0f, // Starting Alpha + 85, // Spread Factor + 3, // Random Origin Offset + 0, // Random Roll Value + 0, // Additional Random Speed + 8, // Particle Color Red + 8, // Particle Color Green + 8, // Particle Color Blue + 8, // Particle Count + 400, // Particle Life + 0.5f, // Particle Scale + 0.5f, // Particle Scale Towards + 0.1f, // Particle Bounce Factor + 0, // Air Friction (stopping particle velocity in air) + -16.0f, // Particle Gravity Factor + 0.0f, // Particle Rolling Friction + alfball // Particle Shader + ); + } + } + + + // Plasma Hit + // should become a plain sprite atlas animation. + if (effect == 6) + { + + } + + + + // Grenade/Rocket/Prox Explosion + // should be an explosion atlas + // plus a smoke atlas that comes in later + // plus a few glquake-ish embers + // plus a couple of sparks that shoots off other sparks + else if (effect == 5 || effect == 4 || effect == 11) + { + + + } + + // BFG, could be just a shockwave. + else if (effect == 9) + { + + + } + + // Blood Sprays for bullets + // should be a nondirectional splat of a center atlas gush + // and then several randomly directed blood drops that roll. all is GE128 + if (effect == 14 && com_blood->integer) + { + colory[0] = 1.0; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 1.0; + colory2[0] = 0.8; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.5; + colory3[0] = 0.6; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.8; + colory4[0] = 0.3; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + //R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0); + //R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4); + } + +} + +// 1999 - a certain competing game +// - high emphasis on atlas animations +// - no alpha blending - only alpha blend, subtractive blend (for grenade smoke) and GE128 alpha testing. +void LFX_ParticleEffect1999 (int effect, vec3_t org, vec3_t dir) +{ + vec3_t origin, sprOrg, sprVel; // laziness + vec4_t colory, colory2, colory3, colory4; + + VectorCopy(org, sprOrg); + VectorCopy(org, origin); + VectorCopy(dir, sprVel); + + // Smoke trails on grenades and rockets + // this should be several smoke atlases along a line. + if (effect == 1) + { + + } + + // Bullet Hit + // a smoke puff, a badly looping spark model, and an occasional ball spark (no stretch) of a random amount from 1 to 6 balls. + if (effect == 2) + { + R_LFX_Generic + (777777, // Particle Type + sprOrg, // Origin + sprVel, // Velocity + 1.0f, // Starting Alpha + 96, // Spread Factor + 4, // Random Origin Offset + 0, // Random Roll Value + 200, // Additional Random Speed + 255, // Particle Color Red + 255, // Particle Color Green + 32, // Particle Color Blue + 5, // Particle Count + 600, // Particle Life + 1, // Particle Scale + 1, // Particle Scale Towards + 0.1f, // Particle Bounce Factor + 0, // Air Friction (stopping particle velocity in air) + -12.0f, // Particle Gravity Factor + 0.0f, // Particle Rolling Friction + addball // Particle Shader + ); + + } + + // Shotgun Hit + // can be just smoke puffs, preferably atlasy. + if (effect == 3) + { + VectorMA( origin, 8, dir, sprOrg ); + sprVel[2] += 20; + R_LFX_Generic + (LFXSMOKE, // Particle Type + sprOrg, // Origin + sprVel, // Velocity + 1.0f, // Starting Alpha + 0, // Spread Factor + 4, // Random Origin Offset + 0, // Random Roll Value + 0, // Additional Random Speed + 255, // Particle Color Red + 255, // Particle Color Green + 255, // Particle Color Blue + 5, // Particle Count + 1200, // Particle Life + 12, // Particle Scale + 12, // Particle Scale Towards + 0, // Particle Bounce Factor + 0, // Air Friction (stopping particle velocity in air) + 0, // Particle Gravity Factor + 10, // Particle Rolling Friction + addsmoke // Particle Shader + ); + } + + // Plasma Hit + // should become a plain sprite atlas animation. + if (effect == 6) + { + + } + + // Lightning Hit + // can become a plain sprite, but we already have that, so..... + if (effect == 8) + { + + } + + + // Grenade/Rocket/Prox Explosion + // should be an explosion atlas, but on later versions there's several more delayed explosion atlases to spice up the variety + else if (effect == 5 || effect == 4 || effect == 11) + { + + + } + + // BFG, could be an expanding sphere with an explosion atlas + else if (effect == 9) + { + + + } + + // Blood Sprays for bullets + // should be an additive smoke puff that doesn't move (but go through an atlas animation) + // as well as a model that has autosprites for ge128 blood sprays, which is kinda cheesy but we can replicate this effect + // withi particles anyhow because we're awesome for having a real particle system ha ha ha ha ha + if (effect == 14 && com_blood->integer) + { + VectorMA( origin, 8, dir, sprOrg ); + sprVel[2] = 0; + sprVel[1] = 0; + sprVel[0] = 0; + R_LFX_Generic + (LFXSMOKE, // Particle Type + sprOrg, // Origin + sprVel, // Velocity + 1.0f, // Starting Alpha + 0, // Spread Factor + 4, // Random Origin Offset + 0, // Random Roll Value + 0, // Additional Random Speed + 255, // Particle Color Red + 0, // Particle Color Green + 0, // Particle Color Blue + 1, // Particle Count + 700, // Particle Life + 8, // Particle Scale + 8, // Particle Scale Towards + 0, // Particle Bounce Factor + 0, // Air Friction (stopping particle velocity in air) + 0, // Particle Gravity Factor + 10, // Particle Rolling Friction + addsmoke // Particle Shader + ); + + R_LFX_Generic + (LFXSMOKE, // Particle Type + sprOrg, // Origin + sprVel, // Velocity + 1.0f, // Starting Alpha + 96, // Spread Factor + 4, // Random Origin Offset + 0, // Random Roll Value + 200, // Additional Random Speed + 255, // Particle Color Red + 0, // Particle Color Green + 0, // Particle Color Blue + 5, // Particle Count + 600, // Particle Life + 1, // Particle Scale + 1, // Particle Scale Towards + 0.1f, // Particle Bounce Factor + 0, // Air Friction (stopping particle velocity in air) + -12.0f, // Particle Gravity Factor + 0.0f, // Particle Rolling Friction + alfsmoke // Particle Shader + ); + } + + // "Blood" Sprays for bullets + if (effect == 14 && !com_blood->integer) + { + // not yet. this should be an additive green puff + } + + + // Blood Spray for a gibbing + if (effect == 16 && com_blood->integer) + { + // not yet. + } + + // Water Splash for bullets - there should only be a polygonal white ring. but we don't do model drawing right now + if (effect == 19) + { + colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0; + colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.6; + colory3[0] = 0.4; colory3[1] = 0.4; colory3[2] = 0.4; colory3[3] = 0.3; + colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0; + VectorScale( dir, 39, sprVel ); + R_LFX_Shock (origin, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 800, 80,14); + } + +} + +void LFX_ParticleEffect (int effect, vec3_t org, vec3_t dir) +{ + + + // choosing particle sets + + if (r_particles->value == 1996) // Mimicing the grand old game + LFX_ParticleEffect1996(effect, org, dir); + else if (r_particles->value == 1997) // Mimicing games for an allegedly 64-bit video game system + LFX_ParticleEffect1997(effect, org, dir); + else if (r_particles->value == 1998) // Mimicing a certain game from Washington state + LFX_ParticleEffect1998(effect, org, dir); + else if (r_particles->value == 1999) // Mimicing a certain competing game + LFX_ParticleEffect1999(effect, org, dir); + else + LFX_ParticleEffect200X(effect, org, dir); + +} + + + diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index 0ee75b8f..aa2a657c 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -6212,6 +6212,9 @@ static void CreateExternalShaders( void ) { if(!tr.placeholderFogShader->defaultShader) tr.placeholderFogAvail = 1; +// leilei - lfx shaders + + LFX_ShaderInit(); } /* diff --git a/code/renderercommon/tr_public.h b/code/renderercommon/tr_public.h index adb6c0ed..165bbc55 100644 --- a/code/renderercommon/tr_public.h +++ b/code/renderercommon/tr_public.h @@ -69,6 +69,8 @@ typedef struct { void (*AddAdditiveLightToScene)( const vec3_t org, float intensity, float r, float g, float b ); void (*RenderScene)( const refdef_t *fd ); + void (*LFX_ParticleEffect)( int effect, const vec3_t origin, const vec3_t velocity ); // leilei - particles + void (*SetColor)( const float *rgba ); // NULL = 1,1,1,1 void (*DrawStretchPic) ( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ); // 0 = white diff --git a/code/renderergl1/tr_init.c b/code/renderergl1/tr_init.c index 08358d16..2a934e93 100644 --- a/code/renderergl1/tr_init.c +++ b/code/renderergl1/tr_init.c @@ -1348,6 +1348,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { re.ClearScene = RE_ClearScene; re.AddRefEntityToScene = RE_AddRefEntityToScene; re.AddPolyToScene = RE_AddPolyToScene; + re.LFX_ParticleEffect = NULL; re.LightForPoint = R_LightForPoint; re.AddLightToScene = RE_AddLightToScene; re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; diff --git a/code/renderergl2/tr_init.c b/code/renderergl2/tr_init.c index 84bbeba2..00646be2 100644 --- a/code/renderergl2/tr_init.c +++ b/code/renderergl2/tr_init.c @@ -1558,6 +1558,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { re.ClearScene = RE_ClearScene; re.AddRefEntityToScene = RE_AddRefEntityToScene; re.AddPolyToScene = RE_AddPolyToScene; + re.LFX_ParticleEffect = NULL; re.LightForPoint = R_LightForPoint; re.AddLightToScene = RE_AddLightToScene; re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; diff --git a/misc/quake3.ico b/misc/quake3.ico index d9a5531bf77b7e289010a01feaceb59ea933e938..5f158b9dddd8bb32c7fa7e1fcc7508a1e730b67c 100644 GIT binary patch literal 10134 zcmeHNeNa?amOnk|fo4D&G$w6SpiN9{32F-{jWT(3UYe#wKtx1ru!U#Sh$6Ovt%yEi z+dc)w&k;mLQDfp4I3xxlAR2~IBV@9Fq-wWjXPqsJq;^`yLP}$cKW0f{4*H1(6-)aFZNACfWyCSeRG;<&TKI@nLO- zCVE#z^cz2-S+l%)2XvmXtUas`BpT4bFPaPy23C*~SE5e&>b-caM+71fz9fp?0#{V2 zv$GQ=Qw+&p8X96XFg{F#OHw~R16|Y`h!6F1_r?27_x%IA?*Er>rLWl0b$_>7Ix3y) zQn~7-YALWwTne zdtLNUp%DX%b}qgTNZFmem2!fVE&9s{^cK%nV2cyb5?Qj5J^^SjXzj0lY&4 zOb{?&I8!P$C^f(a0Rx9YQz_{AFx01#7B*URs)byO4z=h^s|9PcD0S!;zM)=m^0qDU7R>If-)@iknYas{gQAdB~ z03!1gB^h;-fYFjgPh>ggvLT+Rj9T|-}%9;Hw9^n!8am8MHqhF{8RSSY&<3 zWLwCU&XYUKNE`CgXiv6@s`8TQa9$euP7x@`P)HNr+)fd5SCG!)CcUMM3YIy@XKFiz zXEo5c+)pTS<$Gkvy+FyU&QQg=OsXkNrsIW~)VyI1T_{PXE1R?F{Eh;;v7?Z>t2WT# zvXj(&u$)>NDkx;rKhg_3|C4m?Z)wW@-;?g}5QUu?BK@YnBfa|z@K>~8=Y6V?TB+gG zefo#Pxzr0Ee}8l%eO^;WzdgQ<{^h+2`t_+A`uai@{l0NO{r1)|8v5Wc4RxKQ|G0gP z{`7QF`l;-;|CrWjjn+0l`s#juP`P5xPdZomt7g+ez*L0tTQ1 z2hgN;j0N(WV7XaHOfXFCEIuX}rb5=lYW_7m4IaY49C#!jiO6jugxk$162JF8`Xb)7>rWYTgYElFT3TT&l=6zV~@8?pHVjss*lHIZLLyuqU zphr^f?1xQjh2#h)8<#RSpH(l7sVW3KY0rq)Sob zR(sqws%t_zd?;?RKgX$64iov+`E>QVL|<3MevQXXqH;pent*(fT<+k94x3p;2ZH*O zz7Q3@Qhc#T^tFjfML*Z;Quu!3E_H~U10nX)y)PB}w@WUGv#CT8?W6(G@90Cx>;pe4 z+DgjaFBP@hJ#HUPSu6(LV)~^m281V2vdpW z`9G&8_qj@rM;sL@2{}2_xqLc5Yy2fyf_u^M1H|9#9g}FxY!0 zVEJCBokaSnMDbcBMNfSm`5$>0=K-WlIqyeDcym6>^>SX1K+Z7ro&kot~)@#yN*0~ zbw3TYH&B0PJAL=hAJBLI`WfzuEbsmB@*TF&Gx|Zzz^v3+PmgEjiZ_@j4!=n<RVSsl_Fv84Ezxn#EpyfuGeHn`K{F>ZGi^++`&jC?-l1oSeOSj#oc@ z#iF#dnOVz93TNoD@-~+UWaRnqS6AnZMEK(Jm_!=w1*WI2MIwCLnad%ih#-XiFYMy+MR@|>vfNpt5W7qLnH zi6eo_%37Hjn-Eg~ee}!AO=PoCxHclWXgTzxUlGeKO;3+cm^LxSXq@t9Dr9S**K+G+ zJ(*U_pR#b_LO#K0OfUv7UI2ZuRjm!nS22QS!}{C9-q2mZPD`aPpRc*>guAkt5>geAXhyj@B1Nk zKd^yE&g10scxHkgS5Xt?@1HuSi0r`fXWkD%`Mt+7B~!A)o^rV6ZF5hMSLQ|W3_3!O z!Sc}%Mkv`Kk>j8ON^atUik%g5FAQa}4XaGuOd%TpWV+MG^FG~>2*Hz>f=5`m7S$f- z`86E^ZxVx{5MaUN$vbLm1)n>S-Mo4*I5=425xn>Tv9`85&@iu!PZ^}(;BoW&WPI{~ zIHC1;ilS~_w|bDEnA9iZzv}ZmcfI*5ns>dmTI8V!5#)pJy)}}p&M>6(yWTpavO@tm zi^tUM@c1=9v~zW>Lq2x1sN5&80U&U@q^KX11V6(=CRYp~P#lW6PgNcSjYkc)8gc>s4`8fH$bCE#X*`k*a+3-2>wWOVClA^^l6#yaiE7bq zHxU#am@f>{BS{`bjKpnM+66mDe%EDB>OqIYW9K5xgfP*8lIpJa!coegWHTemDEbz1 zAG?Y7Gn|AYWv4`lMsYwfXc7dn3j%M@LvHT#;0>oFPGI44Ci3C<_~2eai3ca5QjhyN z$W1ooM%ZwW^Zadzf;TxNE)-$fd`e*;C_-#XzQ{r2j>3`J$BtJnCXZ6^QG^H_pVZA6 zYB$*3DLy6#nJC}n!%;|=5*^qk95P7KE|uL)0wsuojY1w^=927+$Y2ekwcAJ}^Z@(= zY&cW54G)11NiuUjBGD$SR;a*sN>Mij2bm?0#KE<4J9g)Q4S3$v=f*)^!UH&F%7({l z`U8(&3(qIrhCOB#5>5qq;5U$C|MEqWjZ_X;;V1VEk@|s>Rhfn4CWlBSX=tbz?(yUV zf&qUIYhssnZD-=ZKChe^n0mXhDvm0^eArH5c-ev}v zV0iWp<5~H)oQG+c?pa_PSRp^T5{W-SV}$;<&%;6N*;jrde)fL-+57cp@7I4I@7G6e z2S30vnB#)Ke^`dFr*xtDd-pjE-(xYM;N*@8vcb$1*)qnk`E-55>B?L~=u>{s49+P$ z-~4F-aQ^WH=TF-q3ftVUYv(#ob!FvdF3kT)6aN)wn;V;cekPs9+IPHjwfXc?e+t-p zV%oZOZug-Rl{>b*#f|R7e{t)(wT&>Sj2~0~PE*s>=E8WQ+n><7q9V8Zz=5AtpFFwc zu|Yt3+pY7{8k?G$nhWUG@y4dBSKld!r=A`f{~GY_0|yVj)3$f+NJ!&Wciifz8gmHv zrsl;x@kbgjqlW_Oxl2)#{U@(O2M2%ET7f@(duek=_q)4K>{i!YZEAY&W)J!+~rKx7qhppR2&1h)F8A;l`d$+N; z7EYz|@=WzHSe}vn3#I13on4)$R*W(jclu)sETs90o?lY=)-vat^N;o-9IG`WLl6SS zym#gOn}zw4AB}*zdv=$XmrGme?wi)~veMGh1U8$3H4AtP)n2%C<>$VI`HzRt^D&i| zZ!Iq;+P~FRR$5k;N~FtS)utiEU1&e$J7)x~`usby}@PLO6)WYMEZVXUpj`&hd$f zv-KNOcOGi@4#05jtSd9Jrmn8>{o~AFBg0#*!tCf>d&AzSZ?(=$Ow^>N7JF`dn9clC zZp%K`OFQe1)zrMVDbHz@{A7Ga$c(*P#?p$`7BX9A>&zBz$(@}i!$y2ODz}_Fx6eD?@)Kv??YMRO z?rlG!nTfF>ZJnpzdIWo13Ek83(b;kgU{z`P?h{p2>^_nhJ6r5*uYY`xdkjY{SUmSp zOGCA5p(#c)emr)kSzmvnv!(LU9rp>e+z1sLTH4xLuAMtu-*E0+d*_Xoecq(=$IwR- j{hrfjTbRk&hP|1i?rx6&&nn+P1J9mMy>s)opNIbedj+Nz literal 2734 zcmdUxzmDTJ5XQ%G5UDtTE>oRdrgU}HA>JyF5p24Y>ZBroh}**I^hyfu0qzL`I9*D0 zRADUh`-T#-Sp+FANfBD)kn`u8;fNf|Y-f8r91f=T&Ccu{^mHog-@Y*W9^Uy})<1q_ z_T880p(DccWZL*F#1oh^iBNC>K0V~Ulfv9YnKn=wTTjSXWmyJ9#jRtxaDwAjCH#E^ga zl=E=SIaZ|`)b{jUiSlrQo{{~K^8{}~HV0YetUR6Q5A-chk(_SrKg-kR;InBRF;y?E z>Kl?3&1z+xXvU1 zk{5ekU20o-&Z*B`)nV=mmC%+N^R`Vm42cL@i(}iO(pg1xt$Xk6N(2EXV=wd07^37= zT58$iqnxR}$DH6sJYJojd~;P|?EqLJ56J6oh{Rs@BJOn<2BFh*5XsXpB!x~O&b_w7 z=;l`+v1qReqqc};*SD-neq?99>Y~s8eo(qzx8;8CZ(Vn}ox9`hd=9gnkF(kFW~bu> zrH4owK3Lp;;CMdSj=qmiaX3|u{B^eD$Hgum?{=xUl_5`d$+PvFPo48K z{gJ+%bE8&l?XXRp#&WW_`^@P4n0!_}!2bW%{LI+!I_xn=SoPw3ozK!JBsxS@idwHH zj2V3Cj4stRkrs_hmLS{~Ex0VjotM+7YpQkN+H8E@VdGX2EA&^K;$Q>~#(E2}bex3S zj012UHG#Dh!WcJT6AxogAQ6 z_@TIWAnC90+6Vf<>jw^e55g(>rrM(&Y%t6nqUwf$GVM`Fop_3$7D4qV_%$vno$7X3 zQT@vH2o(XlE&Qz*3Q+=Towq;yxS&hUSCUpd8PvR3_}cSJwp+kbd!a20nW*{v-y3vj z|52;v{0V^j{?=ci3zScWyzHinK6s#SRaNg6H~L2FXR|kw-`SY!n|-bItj{pyH=7mWe(>xt!DEE}lf2eQfwnnMm6r%B#N@x_cJ=$@Up~d%x0ev3|ne z+m!}TSuYjdp!a=r`n-#m3_kx6muJyv{atr@vVJBm1*|x=5yh>IX+KhsI*2az>0b=L E1O0e*V*mgE