2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <base/math.h>
|
2010-10-19 11:37:36 +00:00
|
|
|
#include <engine/demo.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <engine/graphics.h>
|
2009-10-27 14:38:53 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
#include "particles.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/client/render.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <game/generated/client_data.h>
|
2008-01-29 21:39:41 +00:00
|
|
|
|
2021-07-12 09:29:59 +00:00
|
|
|
#include <game/client/gameclient.h>
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CParticles::CParticles()
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
OnReset();
|
|
|
|
m_RenderTrail.m_pParts = this;
|
|
|
|
m_RenderExplosions.m_pParts = this;
|
2022-06-14 17:30:01 +00:00
|
|
|
m_RenderExtra.m_pParts = this;
|
2010-05-29 07:25:38 +00:00
|
|
|
m_RenderGeneral.m_pParts = this;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2008-01-29 21:39:41 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CParticles::OnReset()
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
|
|
|
// reset particles
|
|
|
|
for(int i = 0; i < MAX_PARTICLES; i++)
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
m_aParticles[i].m_PrevPart = i - 1;
|
|
|
|
m_aParticles[i].m_NextPart = i + 1;
|
2008-01-29 21:39:41 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_aParticles[0].m_PrevPart = 0;
|
2020-09-26 19:41:58 +00:00
|
|
|
m_aParticles[MAX_PARTICLES - 1].m_NextPart = -1;
|
2010-05-29 07:25:38 +00:00
|
|
|
m_FirstFree = 0;
|
2008-01-29 21:39:41 +00:00
|
|
|
|
2020-10-26 14:14:07 +00:00
|
|
|
for(int &FirstPart : m_aFirstPart)
|
|
|
|
FirstPart = -1;
|
2008-01-29 21:39:41 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 22:46:54 +00:00
|
|
|
void CParticles::Add(int Group, CParticle *pPart, float TimePassed)
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2010-11-16 23:38:20 +00:00
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
|
|
|
{
|
2011-04-13 18:37:12 +00:00
|
|
|
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
|
2010-11-16 23:38:20 +00:00
|
|
|
if(pInfo->m_Paused)
|
|
|
|
return;
|
|
|
|
}
|
2012-01-09 23:49:31 +00:00
|
|
|
else
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED)
|
2012-01-09 23:49:31 +00:00
|
|
|
return;
|
|
|
|
}
|
2010-11-16 23:38:20 +00:00
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
if(m_FirstFree == -1)
|
2008-01-29 21:39:41 +00:00
|
|
|
return;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-01-29 21:39:41 +00:00
|
|
|
// remove from the free list
|
2010-05-29 07:25:38 +00:00
|
|
|
int Id = m_FirstFree;
|
|
|
|
m_FirstFree = m_aParticles[Id].m_NextPart;
|
2010-11-24 00:08:51 +00:00
|
|
|
if(m_FirstFree != -1)
|
|
|
|
m_aParticles[m_FirstFree].m_PrevPart = -1;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-01-29 21:39:41 +00:00
|
|
|
// copy data
|
2010-05-29 07:25:38 +00:00
|
|
|
m_aParticles[Id] = *pPart;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-01-29 21:39:41 +00:00
|
|
|
// insert to the group list
|
2010-05-29 07:25:38 +00:00
|
|
|
m_aParticles[Id].m_PrevPart = -1;
|
|
|
|
m_aParticles[Id].m_NextPart = m_aFirstPart[Group];
|
|
|
|
if(m_aFirstPart[Group] != -1)
|
|
|
|
m_aParticles[m_aFirstPart[Group]].m_PrevPart = Id;
|
|
|
|
m_aFirstPart[Group] = Id;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-01-29 21:39:41 +00:00
|
|
|
// set some parameters
|
2019-04-11 22:46:54 +00:00
|
|
|
m_aParticles[Id].m_Life = TimePassed;
|
2008-01-29 21:39:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CParticles::Update(float TimePassed)
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2018-08-24 03:56:33 +00:00
|
|
|
if(TimePassed <= 0.0f)
|
|
|
|
return;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
static float FrictionFraction = 0;
|
|
|
|
FrictionFraction += TimePassed;
|
2008-01-29 21:39:41 +00:00
|
|
|
|
2018-02-04 15:00:47 +00:00
|
|
|
if(FrictionFraction > 2.0f) // safety messure
|
2010-05-29 07:25:38 +00:00
|
|
|
FrictionFraction = 0;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int FrictionCount = 0;
|
|
|
|
while(FrictionFraction > 0.05f)
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
FrictionCount++;
|
|
|
|
FrictionFraction -= 0.05f;
|
2008-01-29 21:39:41 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-10-26 14:14:07 +00:00
|
|
|
for(int &FirstPart : m_aFirstPart)
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2020-10-26 14:14:07 +00:00
|
|
|
int i = FirstPart;
|
2008-01-29 21:39:41 +00:00
|
|
|
while(i != -1)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int Next = m_aParticles[i].m_NextPart;
|
|
|
|
//m_aParticles[i].vel += flow_get(m_aParticles[i].pos)*time_passed * m_aParticles[i].flow_affected;
|
2020-09-26 19:41:58 +00:00
|
|
|
m_aParticles[i].m_Vel.y += m_aParticles[i].m_Gravity * TimePassed;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int f = 0; f < FrictionCount; f++) // apply friction
|
|
|
|
m_aParticles[i].m_Vel *= m_aParticles[i].m_Friction;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-01-29 21:39:41 +00:00
|
|
|
// move the point
|
2020-09-26 19:41:58 +00:00
|
|
|
vec2 Vel = m_aParticles[i].m_Vel * TimePassed;
|
2022-06-14 17:30:01 +00:00
|
|
|
if(m_aParticles[i].m_Collides)
|
|
|
|
{
|
|
|
|
Collision()->MovePoint(&m_aParticles[i].m_Pos, &Vel, 0.1f + 0.9f * random_float(), NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_aParticles[i].m_Pos += Vel;
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
m_aParticles[i].m_Vel = Vel * (1.0f / TimePassed);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_aParticles[i].m_Life += TimePassed;
|
|
|
|
m_aParticles[i].m_Rot += TimePassed * m_aParticles[i].m_Rotspeed;
|
2008-01-29 21:39:41 +00:00
|
|
|
|
|
|
|
// check particle death
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_aParticles[i].m_Life > m_aParticles[i].m_LifeSpan)
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
|
|
|
// remove it from the group list
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_aParticles[i].m_PrevPart != -1)
|
|
|
|
m_aParticles[m_aParticles[i].m_PrevPart].m_NextPart = m_aParticles[i].m_NextPart;
|
2008-01-29 21:39:41 +00:00
|
|
|
else
|
2020-10-26 14:14:07 +00:00
|
|
|
FirstPart = m_aParticles[i].m_NextPart;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_aParticles[i].m_NextPart != -1)
|
|
|
|
m_aParticles[m_aParticles[i].m_NextPart].m_PrevPart = m_aParticles[i].m_PrevPart;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-01-29 21:39:41 +00:00
|
|
|
// insert to the free list
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_FirstFree != -1)
|
|
|
|
m_aParticles[m_FirstFree].m_PrevPart = i;
|
|
|
|
m_aParticles[i].m_PrevPart = -1;
|
|
|
|
m_aParticles[i].m_NextPart = m_FirstFree;
|
|
|
|
m_FirstFree = i;
|
2008-01-29 21:39:41 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
i = Next;
|
2008-01-29 21:39:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CParticles::OnRender()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-04-08 09:22:44 +00:00
|
|
|
if(Client()->State() < IClient::STATE_ONLINE)
|
|
|
|
return;
|
|
|
|
|
2016-06-28 21:35:59 +00:00
|
|
|
set_new_tick();
|
2021-06-23 05:05:49 +00:00
|
|
|
static int64_t LastTime = 0;
|
|
|
|
int64_t t = time();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-10-19 11:37:36 +00:00
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
|
|
|
{
|
2011-04-13 18:37:12 +00:00
|
|
|
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
|
2010-10-19 11:37:36 +00:00
|
|
|
if(!pInfo->m_Paused)
|
2020-09-26 19:41:58 +00:00
|
|
|
Update((float)((t - LastTime) / (double)time_freq()) * pInfo->m_Speed);
|
2010-10-19 11:37:36 +00:00
|
|
|
}
|
|
|
|
else
|
2012-01-09 23:49:31 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED))
|
|
|
|
Update((float)((t - LastTime) / (double)time_freq()));
|
2012-01-09 23:49:31 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
LastTime = t;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
void CParticles::OnInit()
|
|
|
|
{
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
2021-09-13 21:14:04 +00:00
|
|
|
m_ParticleQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
for(int i = 0; i <= (SPRITE_PART9 - SPRITE_PART_SLICE); ++i)
|
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
RenderTools()->QuadContainerAddSprite(m_ParticleQuadContainerIndex, 1.f);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
2021-09-13 21:14:04 +00:00
|
|
|
Graphics()->QuadContainerUpload(m_ParticleQuadContainerIndex);
|
2022-06-14 17:30:01 +00:00
|
|
|
|
|
|
|
m_ExtraParticleQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
|
|
|
|
|
|
|
// TODO: Use a loop similar to the one for m_ParticleQuadContainerIndex if you add more additional particles
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
RenderTools()->QuadContainerAddSprite(m_ExtraParticleQuadContainerIndex, 1.f);
|
|
|
|
Graphics()->QuadContainerUpload(m_ExtraParticleQuadContainerIndex);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
|
|
|
|
2020-12-23 13:55:49 +00:00
|
|
|
bool CParticles::ParticleIsVisibleOnScreen(const vec2 &CurPos, float CurSize)
|
|
|
|
{
|
|
|
|
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
|
|
|
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
|
|
|
|
2020-12-29 14:52:31 +00:00
|
|
|
// for simplicity assume the worst case rotation, that increases the bounding box around the particle by its diagonal
|
|
|
|
const float SqrtOf2 = sqrtf(2);
|
|
|
|
CurSize = SqrtOf2 * CurSize;
|
|
|
|
|
2020-12-23 13:55:49 +00:00
|
|
|
// always uses the mid of the particle
|
|
|
|
float SizeHalf = CurSize / 2;
|
|
|
|
|
|
|
|
return CurPos.x + SizeHalf >= ScreenX0 && CurPos.x - SizeHalf <= ScreenX1 && CurPos.y + SizeHalf >= ScreenY0 && CurPos.y - SizeHalf <= ScreenY1;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CParticles::RenderGroup(int Group)
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2022-06-25 08:39:39 +00:00
|
|
|
IGraphics::CTextureHandle *aParticles = GameClient()->m_ParticlesSkin.m_aSpriteParticles;
|
2022-06-14 17:30:01 +00:00
|
|
|
int FirstParticleOffset = SPRITE_PART_SLICE;
|
|
|
|
int ParticleQuadContainerIndex = m_ParticleQuadContainerIndex;
|
|
|
|
if(Group == GROUP_EXTRA)
|
|
|
|
{
|
2022-06-25 08:39:39 +00:00
|
|
|
aParticles = GameClient()->m_ExtrasSkin.m_aSpriteParticles;
|
2022-06-14 17:30:01 +00:00
|
|
|
FirstParticleOffset = SPRITE_PART_SNOWFLAKE;
|
|
|
|
ParticleQuadContainerIndex = m_ExtraParticleQuadContainerIndex;
|
|
|
|
}
|
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
// don't use the buffer methods here, else the old renderer gets many draw calls
|
2020-08-29 10:10:38 +00:00
|
|
|
if(Graphics()->IsQuadContainerBufferingEnabled())
|
2018-03-13 20:52:44 +00:00
|
|
|
{
|
|
|
|
int i = m_aFirstPart[Group];
|
|
|
|
|
|
|
|
static IGraphics::SRenderSpriteInfo s_aParticleRenderInfo[MAX_PARTICLES];
|
|
|
|
|
|
|
|
int CurParticleRenderCount = 0;
|
|
|
|
|
|
|
|
// batching makes sense for stuff like ninja particles
|
2022-07-01 04:42:36 +00:00
|
|
|
ColorRGBA LastColor;
|
2018-03-13 20:52:44 +00:00
|
|
|
int LastQuadOffset = 0;
|
|
|
|
|
|
|
|
if(i != -1)
|
|
|
|
{
|
2022-06-14 17:30:01 +00:00
|
|
|
float Alpha = m_aParticles[i].m_Color.a;
|
|
|
|
if(m_aParticles[i].m_UseAlphaFading)
|
|
|
|
{
|
|
|
|
float a = m_aParticles[i].m_Life / m_aParticles[i].m_LifeSpan;
|
|
|
|
Alpha = mix(m_aParticles[i].m_StartAlpha, m_aParticles[i].m_EndAlpha, a);
|
|
|
|
}
|
2022-07-01 04:42:36 +00:00
|
|
|
LastColor.r = m_aParticles[i].m_Color.r;
|
|
|
|
LastColor.g = m_aParticles[i].m_Color.g;
|
|
|
|
LastColor.b = m_aParticles[i].m_Color.b;
|
|
|
|
LastColor.a = Alpha;
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
Graphics()->SetColor(
|
|
|
|
m_aParticles[i].m_Color.r,
|
|
|
|
m_aParticles[i].m_Color.g,
|
|
|
|
m_aParticles[i].m_Color.b,
|
2022-06-14 17:30:01 +00:00
|
|
|
Alpha);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
LastQuadOffset = m_aParticles[i].m_Spr;
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
while(i != -1)
|
|
|
|
{
|
|
|
|
int QuadOffset = m_aParticles[i].m_Spr;
|
|
|
|
float a = m_aParticles[i].m_Life / m_aParticles[i].m_LifeSpan;
|
|
|
|
vec2 p = m_aParticles[i].m_Pos;
|
|
|
|
float Size = mix(m_aParticles[i].m_StartSize, m_aParticles[i].m_EndSize, a);
|
2022-06-14 17:30:01 +00:00
|
|
|
float Alpha = m_aParticles[i].m_Color.a;
|
|
|
|
if(m_aParticles[i].m_UseAlphaFading)
|
|
|
|
{
|
|
|
|
Alpha = mix(m_aParticles[i].m_StartAlpha, m_aParticles[i].m_EndAlpha, a);
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
|
2020-12-23 13:55:49 +00:00
|
|
|
// the current position, respecting the size, is inside the viewport, render it, else ignore
|
|
|
|
if(ParticleIsVisibleOnScreen(p, Size))
|
2018-03-13 20:52:44 +00:00
|
|
|
{
|
2022-07-01 04:42:36 +00:00
|
|
|
if((size_t)CurParticleRenderCount == gs_GraphicsMaxParticlesRenderCount || LastColor.r != m_aParticles[i].m_Color.r || LastColor.g != m_aParticles[i].m_Color.g || LastColor.b != m_aParticles[i].m_Color.b || LastColor.a != Alpha || LastQuadOffset != QuadOffset)
|
2020-12-23 13:55:49 +00:00
|
|
|
{
|
2022-06-14 17:30:01 +00:00
|
|
|
Graphics()->TextureSet(aParticles[LastQuadOffset - FirstParticleOffset]);
|
|
|
|
Graphics()->RenderQuadContainerAsSpriteMultiple(ParticleQuadContainerIndex, LastQuadOffset - FirstParticleOffset, CurParticleRenderCount, s_aParticleRenderInfo);
|
2020-12-23 13:55:49 +00:00
|
|
|
CurParticleRenderCount = 0;
|
|
|
|
LastQuadOffset = QuadOffset;
|
|
|
|
|
|
|
|
Graphics()->SetColor(
|
|
|
|
m_aParticles[i].m_Color.r,
|
|
|
|
m_aParticles[i].m_Color.g,
|
|
|
|
m_aParticles[i].m_Color.b,
|
2022-06-14 17:30:01 +00:00
|
|
|
Alpha);
|
2020-12-23 13:55:49 +00:00
|
|
|
|
2022-07-01 04:42:36 +00:00
|
|
|
LastColor.r = m_aParticles[i].m_Color.r;
|
|
|
|
LastColor.g = m_aParticles[i].m_Color.g;
|
|
|
|
LastColor.b = m_aParticles[i].m_Color.b;
|
|
|
|
LastColor.a = Alpha;
|
2020-12-23 13:55:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s_aParticleRenderInfo[CurParticleRenderCount].m_Pos[0] = p.x;
|
|
|
|
s_aParticleRenderInfo[CurParticleRenderCount].m_Pos[1] = p.y;
|
|
|
|
s_aParticleRenderInfo[CurParticleRenderCount].m_Scale = Size;
|
|
|
|
s_aParticleRenderInfo[CurParticleRenderCount].m_Rotation = m_aParticles[i].m_Rot;
|
|
|
|
|
|
|
|
++CurParticleRenderCount;
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
i = m_aParticles[i].m_NextPart;
|
|
|
|
}
|
|
|
|
|
2022-06-14 17:30:01 +00:00
|
|
|
Graphics()->TextureSet(aParticles[LastQuadOffset - FirstParticleOffset]);
|
|
|
|
Graphics()->RenderQuadContainerAsSpriteMultiple(ParticleQuadContainerIndex, LastQuadOffset - FirstParticleOffset, CurParticleRenderCount, s_aParticleRenderInfo);
|
2018-03-13 20:52:44 +00:00
|
|
|
}
|
|
|
|
else
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2018-03-13 20:52:44 +00:00
|
|
|
int i = m_aFirstPart[Group];
|
2008-01-29 21:39:41 +00:00
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->BlendNormal();
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->WrapClamp();
|
2008-01-29 21:39:41 +00:00
|
|
|
|
2018-03-13 20:52:44 +00:00
|
|
|
while(i != -1)
|
|
|
|
{
|
|
|
|
float a = m_aParticles[i].m_Life / m_aParticles[i].m_LifeSpan;
|
|
|
|
vec2 p = m_aParticles[i].m_Pos;
|
|
|
|
float Size = mix(m_aParticles[i].m_StartSize, m_aParticles[i].m_EndSize, a);
|
2022-06-14 17:30:01 +00:00
|
|
|
float Alpha = m_aParticles[i].m_Color.a;
|
|
|
|
if(m_aParticles[i].m_UseAlphaFading)
|
|
|
|
{
|
|
|
|
Alpha = mix(m_aParticles[i].m_StartAlpha, m_aParticles[i].m_EndAlpha, a);
|
|
|
|
}
|
2008-01-29 21:39:41 +00:00
|
|
|
|
2020-12-23 13:55:49 +00:00
|
|
|
// the current position, respecting the size, is inside the viewport, render it, else ignore
|
|
|
|
if(ParticleIsVisibleOnScreen(p, Size))
|
|
|
|
{
|
2022-06-14 17:30:01 +00:00
|
|
|
Graphics()->TextureSet(aParticles[m_aParticles[i].m_Spr - FirstParticleOffset]);
|
2020-12-23 13:55:49 +00:00
|
|
|
Graphics()->QuadsBegin();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-12-23 13:55:49 +00:00
|
|
|
Graphics()->QuadsSetRotation(m_aParticles[i].m_Rot);
|
2018-03-13 20:52:44 +00:00
|
|
|
|
2020-12-23 13:55:49 +00:00
|
|
|
Graphics()->SetColor(
|
|
|
|
m_aParticles[i].m_Color.r,
|
|
|
|
m_aParticles[i].m_Color.g,
|
|
|
|
m_aParticles[i].m_Color.b,
|
2022-06-14 17:30:01 +00:00
|
|
|
Alpha);
|
2020-12-23 13:55:49 +00:00
|
|
|
|
|
|
|
IGraphics::CQuadItem QuadItem(p.x, p.y, Size, Size);
|
|
|
|
Graphics()->QuadsDraw(&QuadItem, 1);
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
}
|
2018-03-13 20:52:44 +00:00
|
|
|
|
|
|
|
i = m_aParticles[i].m_NextPart;
|
|
|
|
}
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->WrapNormal();
|
2018-03-13 20:52:44 +00:00
|
|
|
Graphics()->BlendNormal();
|
2008-01-29 21:39:41 +00:00
|
|
|
}
|
|
|
|
}
|