390 lines
9.3 KiB
C
390 lines
9.3 KiB
C
#include "cg_local.h"
|
|
#include "cg_screenfx.h"
|
|
|
|
// this is the list of currently drawing fx and their start times and end times
|
|
screenFX_t theScreenFX;
|
|
|
|
int CG_GetScreenEffectEndTime(int event)
|
|
{
|
|
switch (event)
|
|
{
|
|
case SCREENFX_TRANSPORTER:
|
|
return cg.time + 1000;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// maybe play a sound or something?
|
|
void CG_BeginScreenEffect(int event)
|
|
{
|
|
switch (event)
|
|
{
|
|
case SCREENFX_TRANSPORTER:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// when adding a new effect, we'll either take an empty slot in theScreenFX or
|
|
//overwrite the oldest effect
|
|
void CG_AddFullScreenEffect(int screenfx, int clientNum)
|
|
{
|
|
int i = 0, oldestTime = cg.time, oldestEffect = 0;
|
|
|
|
if (clientNum != cg.predictedPlayerState.clientNum)
|
|
{ // only add screen effects for our client
|
|
return;
|
|
}
|
|
for (i = 0; i < MAX_SCREENFX; i++)
|
|
{
|
|
// if we already have one of these effects going, just add to the duration of
|
|
//the existing one...don't create a new instance of the same effect
|
|
if (theScreenFX.events[i] == screenfx)
|
|
{
|
|
theScreenFX.cgStartTimes[i] = cg.time;
|
|
theScreenFX.cgEndTimes[i] = CG_GetScreenEffectEndTime(screenfx);
|
|
return;
|
|
}
|
|
else if (theScreenFX.cgStartTimes[i])
|
|
{
|
|
if (theScreenFX.cgStartTimes[i] < oldestTime)
|
|
{
|
|
oldestTime = theScreenFX.cgStartTimes[i];
|
|
oldestEffect = i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oldestTime = theScreenFX.cgStartTimes[i];
|
|
oldestEffect = i;
|
|
}
|
|
}
|
|
theScreenFX.events[oldestEffect] = screenfx;
|
|
theScreenFX.cgStartTimes[oldestEffect] = cg.time;
|
|
theScreenFX.cgEndTimes[oldestEffect] = CG_GetScreenEffectEndTime(screenfx);
|
|
CG_BeginScreenEffect(screenfx);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===============
|
|
CG_DrawScreenQuad
|
|
|
|
===============
|
|
*/
|
|
|
|
|
|
static void CG_DrawScreenQuad(float alpha, qhandle_t screenshader)
|
|
{
|
|
refEntity_t ent;
|
|
float radius;
|
|
|
|
// ragePro systems can't fade blends, so don't obscure the screen
|
|
if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
|
|
return;
|
|
}
|
|
|
|
if (cg.refdef.fov_x > 120)
|
|
{
|
|
return; // Too wide to show this.
|
|
}
|
|
else if (cg.refdef.fov_x > 80)
|
|
{
|
|
radius = 8.0 + (cg.refdef.fov_x - 80)*0.2;
|
|
}
|
|
else
|
|
{
|
|
radius = 8.0;
|
|
}
|
|
|
|
memset( &ent, 0, sizeof( ent ) );
|
|
ent.reType = RT_SPRITE;
|
|
ent.renderfx = RF_FIRST_PERSON;
|
|
|
|
VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );
|
|
|
|
ent.data.sprite.radius = radius;
|
|
ent.customShader = screenshader;
|
|
ent.shaderRGBA[0] = alpha * 255;
|
|
ent.shaderRGBA[1] = alpha * 255;
|
|
ent.shaderRGBA[2] = alpha * 255;
|
|
ent.shaderRGBA[3] = 255;
|
|
trap_R_AddRefEntityToScene( &ent );
|
|
}
|
|
|
|
/*
|
|
static void CG_DrawDirectionalScreenQuad(float alpha, qhandle_t screenshader)
|
|
{
|
|
refEntity_t ent;
|
|
vec3_t screencenter;
|
|
byte topleft, topright, lowleft, lowright, top, low, left, right;
|
|
float val;
|
|
|
|
// ragePro systems can't fade blends, so don't obscure the screen
|
|
if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
|
|
return;
|
|
}
|
|
|
|
// Set up all the basic info about this refentity
|
|
VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], screencenter);
|
|
|
|
memset( &ent, 0, sizeof( ent ) );
|
|
ent.reType = RT_ALPHAVERTPOLY;
|
|
ent.renderfx = RF_FIRST_PERSON;
|
|
|
|
ent.data.sprite.radius = 4;
|
|
ent.customShader = screenshader;
|
|
* (unsigned int *) ent.shaderRGBA = 0xffffffff;
|
|
* (unsigned int *) ent.data.sprite.vertRGBA[0] = 0xffffffff;
|
|
* (unsigned int *) ent.data.sprite.vertRGBA[1] = 0xffffffff;
|
|
* (unsigned int *) ent.data.sprite.vertRGBA[2] = 0xffffffff;
|
|
* (unsigned int *) ent.data.sprite.vertRGBA[3] = 0xffffffff;
|
|
|
|
// left
|
|
val = alpha*(0.5 + 0.5*(cg.damageX - fabs(cg.damageY)));
|
|
if (val<0)
|
|
left=0;
|
|
else if (val>1.0)
|
|
left=255;
|
|
else
|
|
left=255.0*val;
|
|
|
|
// upper left
|
|
val = alpha*(0.5*(cg.damageX + cg.damageY));
|
|
if (val<0)
|
|
topleft=0;
|
|
else if (val>1.0)
|
|
topleft=255;
|
|
else
|
|
topleft=255.0*val;
|
|
|
|
// top
|
|
val = alpha*(0.5 + 0.5*(-fabs(cg.damageX) + cg.damageY));
|
|
if (val<0)
|
|
top=0;
|
|
else if (val>1.0)
|
|
top=255;
|
|
else
|
|
top=255.0*val;
|
|
|
|
// upper right
|
|
val = alpha*(0.5*(-cg.damageX + cg.damageY));
|
|
if (val<0)
|
|
topright=0;
|
|
else if (val>1.0)
|
|
topright=255;
|
|
else
|
|
topright=255.0*val;
|
|
|
|
// right
|
|
val = alpha*(0.5 + 0.5*(-cg.damageX - fabs(cg.damageY)));
|
|
if (val<0)
|
|
right=0;
|
|
else if (val>1.0)
|
|
right=255;
|
|
else
|
|
right=255.0*val;
|
|
|
|
// lower right
|
|
val = alpha*(0.5*(-cg.damageX - cg.damageY));
|
|
if (val<0)
|
|
lowright=0;
|
|
else if (val>1.0)
|
|
lowright=255;
|
|
else
|
|
lowright=255.0*val;
|
|
|
|
// bottom
|
|
val = alpha*(0.5 + 0.5*(-fabs(cg.damageX) - cg.damageY));
|
|
if (val<0)
|
|
low=0;
|
|
else if (val>1.0)
|
|
low=255;
|
|
else
|
|
low=255.0*val;
|
|
|
|
// lower left
|
|
val = alpha*(0.5*(cg.damageX - cg.damageY));
|
|
if (val<0)
|
|
lowleft=0;
|
|
else if (val>1.0)
|
|
lowleft=255;
|
|
else
|
|
lowleft=255.0*val;
|
|
|
|
|
|
// Draw the upper left corner
|
|
VectorMA(screencenter, 4, cg.refdef.viewaxis[1], ent.origin);
|
|
VectorMA(ent.origin, 4, cg.refdef.viewaxis[2], ent.origin);
|
|
ent.data.sprite.vertRGBA[0][3] = topleft;
|
|
ent.data.sprite.vertRGBA[1][3] = top;
|
|
ent.data.sprite.vertRGBA[2][3] = 0;
|
|
ent.data.sprite.vertRGBA[3][3] = left;
|
|
trap_R_AddRefEntityToScene( &ent );
|
|
|
|
|
|
// Draw topper right corner
|
|
VectorMA(screencenter, -4, cg.refdef.viewaxis[1], ent.origin);
|
|
VectorMA(ent.origin, 4, cg.refdef.viewaxis[2], ent.origin);
|
|
ent.data.sprite.vertRGBA[0][3] = top;
|
|
ent.data.sprite.vertRGBA[1][3] = topright;
|
|
ent.data.sprite.vertRGBA[2][3] = right;
|
|
ent.data.sprite.vertRGBA[3][3] = 0;
|
|
trap_R_AddRefEntityToScene( &ent );
|
|
|
|
|
|
// Draw lower right corner
|
|
VectorMA(screencenter, -4, cg.refdef.viewaxis[1], ent.origin);
|
|
VectorMA(ent.origin, -4, cg.refdef.viewaxis[2], ent.origin);
|
|
ent.data.sprite.vertRGBA[0][3] = 0;
|
|
ent.data.sprite.vertRGBA[1][3] = right;
|
|
ent.data.sprite.vertRGBA[2][3] = lowright;
|
|
ent.data.sprite.vertRGBA[3][3] = low;
|
|
trap_R_AddRefEntityToScene( &ent );
|
|
|
|
|
|
// Draw lower left corner
|
|
VectorMA(screencenter, 4, cg.refdef.viewaxis[1], ent.origin);
|
|
VectorMA(ent.origin, -4, cg.refdef.viewaxis[2], ent.origin);
|
|
ent.data.sprite.vertRGBA[0][3] = left;
|
|
ent.data.sprite.vertRGBA[1][3] = 0;
|
|
ent.data.sprite.vertRGBA[2][3] = low;
|
|
ent.data.sprite.vertRGBA[3][3] = lowleft;
|
|
trap_R_AddRefEntityToScene( &ent );
|
|
|
|
}
|
|
*/
|
|
|
|
static void CG_DrawScreenBlob(float redalpha, float greenalpha)
|
|
{
|
|
refEntity_t ent;
|
|
float alphascale;
|
|
float bluealpha = 0;
|
|
|
|
// ragePro systems can't fade blends, so don't obscure the screen
|
|
if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
|
|
return;
|
|
}
|
|
|
|
memset( &ent, 0, sizeof( ent ) );
|
|
ent.reType = RT_SPRITE;
|
|
ent.renderfx = RF_FIRST_PERSON;
|
|
|
|
// Available input:
|
|
// cg.damageValue: Range from 0 to 1, indicating the amount of damage.
|
|
// cg.damageX and cg_damageY: Range from -1 to 1, indicating the location of the damage.
|
|
|
|
VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );
|
|
VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin );
|
|
VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin );
|
|
|
|
// Here's the scoop: The closer we are to the center, the more transparent this blob is.
|
|
alphascale = (2*fabs(cg.damageX)+fabs(cg.damageY))/3.0;
|
|
redalpha *= alphascale;
|
|
greenalpha *= alphascale;
|
|
|
|
if (redalpha > greenalpha)
|
|
{
|
|
ent.data.sprite.radius = cg.damageValue * 15 * redalpha;
|
|
}
|
|
else
|
|
{
|
|
ent.data.sprite.radius = cg.damageShieldValue * 15 * greenalpha;
|
|
}
|
|
|
|
if (redalpha < 0.01)
|
|
{ // Just shield damage
|
|
ent.customShader = cgs.media.shieldBlobShader;
|
|
// Set all colors to the same as green, since the shader is green
|
|
redalpha = bluealpha = greenalpha;
|
|
}
|
|
else if (greenalpha < 0.01)
|
|
{ // Just pain damage
|
|
ent.customShader = cgs.media.painBlobShader;
|
|
// Set all colors to the same as red, since the shader is red
|
|
greenalpha = bluealpha = redalpha;
|
|
}
|
|
else
|
|
{ // Both
|
|
ent.customShader = cgs.media.painShieldBlobShader;
|
|
}
|
|
|
|
ent.shaderRGBA[0] = 0xff * redalpha;
|
|
ent.shaderRGBA[1] = 0xff * greenalpha;
|
|
ent.shaderRGBA[2] = 0xff * bluealpha;
|
|
ent.shaderRGBA[3] = 0xff;
|
|
trap_R_AddRefEntityToScene( &ent );
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawFullScreenEffect(int screenfx, int start, int end)
|
|
{
|
|
float alpha;
|
|
|
|
alpha = (float)(end-cg.time)/(float)(end-start);
|
|
|
|
switch (screenfx)
|
|
{
|
|
case SCREENFX_TRANSPORTER:
|
|
CG_DrawScreenQuad(alpha, cgs.media.teleportEffectShader);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void CG_DrawFullScreenFX( void )
|
|
{
|
|
int i = 0, t;
|
|
float alpha, redalpha, greenalpha;
|
|
|
|
if ( (cg.snap->ps.clientNum != cg.predictedPlayerState.clientNum) || cg.renderingThirdPerson )
|
|
{
|
|
return;
|
|
}
|
|
|
|
t = cg.time - cg.damageTime;
|
|
if ( t > 0 && t < DAMAGE_TIME)
|
|
{ // Draw the blobs.
|
|
alpha = 1.0 - ((float)t / (float)DAMAGE_TIME);
|
|
|
|
redalpha = alpha*cg.damageValue*1.5;
|
|
if (redalpha > 1.0)
|
|
{
|
|
redalpha = 1.0;
|
|
}
|
|
|
|
greenalpha = alpha*cg.damageShieldValue*1.5;
|
|
if (greenalpha > 1.0)
|
|
{
|
|
greenalpha = 1.0;
|
|
}
|
|
|
|
CG_DrawScreenBlob(redalpha, greenalpha);
|
|
}
|
|
|
|
for (i = 0; i < MAX_SCREENFX; i++)
|
|
{
|
|
if (theScreenFX.cgEndTimes[i])
|
|
{
|
|
if (theScreenFX.cgEndTimes[i] <= cg.time)
|
|
{
|
|
// remove this effect
|
|
theScreenFX.events[i] = 0;
|
|
theScreenFX.cgStartTimes[i] = 0;
|
|
theScreenFX.cgEndTimes[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
// still drawing this effect
|
|
CG_DrawFullScreenEffect(theScreenFX.events[i],theScreenFX.cgStartTimes[i],theScreenFX.cgEndTimes[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|