1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 // -------------------------------------------------------------------------
4 // Created: 06/02/2015 by Filipe amim
6 // -------------------------------------------------------------------------
8 ////////////////////////////////////////////////////////////////////////////
11 #include <CryMath/FinalizingSpline.h>
12 #include "ParticleCommon.h"
13 #include "ParticleDebug.h"
14 #include "ParticleContainer.h"
15 #include "ParticleComponent.h"
16 #include "ParticleComponentRuntime.h"
17 #include "ParticleEffect.h"
18 #include "ParticleEmitter.h"
19 #include "Features/FeatureCollision.h"
26 #if !defined(_RELEASE)
31 const ColorB
black(0, 0, 0);
32 const ColorB
white(255, 255, 255);
33 const ColorF
whiteF(1.0f
, 1.0f
, 1.0f
);
34 const ColorB
lightOrange(255, 198, 128);
35 const ColorB
red(192, 23, 32);
36 const ColorB
darkRed(96, 0, 0);
38 const float startPos
= 1.0f
/ 40.0f
;
39 const float barSz
= 1.0f
/ 192.0f
;
40 const float barGap
= 1.0f
/ 24.0f
;
42 void DebugDrawEffect(CParticleEffect
* pEffect
, size_t effectBarIdx
)
46 IRenderer
* pRender
= gEnv
->pRenderer
;
47 IRenderAuxGeom
* pRenderAux
= gEnv
->pRenderer
->GetIRenderAuxGeom();
49 const float screenWidth
= pRenderAux
->GetCamera().GetViewSurfaceX();
50 const float screenHeight
= pRenderAux
->GetCamera().GetViewSurfaceZ();
52 const Vec2 screenSz
= Vec2(screenWidth
, screenHeight
);
53 const Vec2 pixSz
= Vec2(1.0f
/ screenWidth
, 1.0f
/ screenHeight
);
55 size_t numEmitters
= pEffect
->GetEmitterCount();
56 const Vec2 emitterSz
= Vec2(barSz
, 0.9f
/ numEmitters
);
57 const Vec2 emitterLoc
= Vec2(effectBarIdx
* barGap
+ startPos
, startPos
);
59 Vec3 pos
= Vec2(effectBarIdx
* barGap
+ startPos
, startPos
);
60 for (size_t i
= 0; i
< numEmitters
; ++i
)
64 box
.max
.x
= box
.min
.x
+ std::max(emitterSz
.x
, pixSz
.x
);
65 box
.max
.y
= box
.min
.y
+ std::max(emitterSz
.y
- pixSz
.y
, pixSz
.y
);
66 ColorB color
= pEffect
->GetEmitter(i
).m_active
? red
: darkRed
;
67 pRenderAux
->DrawAABB(box
, true, color
, eBBD_Faceted
);
72 screenSz
.x
* (effectBarIdx
* barGap
+ startPos
),
73 screenSz
.y
* 0.975f
, 1.0f
, whiteF
, false,
78 void DebugDrawComponentRuntime(CParticleComponentRuntime
* pRuntime
, size_t emitterBarIdx
, size_t barIdx
)
80 IRenderAuxGeom
* pRenderAux
= gEnv
->pRenderer
->GetIRenderAuxGeom();
81 SAuxGeomRenderFlags prevFlags
= pRenderAux
->GetRenderFlags();
82 SAuxGeomRenderFlags curFlags
= prevFlags
;
83 curFlags
.SetMode2D3DFlag(e_Mode2D
);
84 curFlags
.SetDepthTestFlag(e_DepthTestOff
);
85 curFlags
.SetDepthWriteFlag(e_DepthWriteOff
);
86 pRenderAux
->SetRenderFlags(curFlags
);
88 const float screenWidth
= float(pRenderAux
->GetCamera().GetViewSurfaceX());
89 const float screenHeight
= float(pRenderAux
->GetCamera().GetViewSurfaceZ());
91 const SUpdateContext context
= SUpdateContext(pRuntime
);
92 const CParticleContainer
& container
= context
.m_container
;
93 const SComponentParams
& params
= context
.m_params
;
94 const uint numInstances
= pRuntime
->GetNumInstances();
95 IPidStream parentIds
= container
.GetIPidStream(EPDT_ParentId
);
96 IFStream normAges
= container
.GetIFStream(EPDT_NormalAge
);
97 const Vec2 screenSz
= Vec2(screenWidth
, screenHeight
);
98 const Vec2 pixSz
= Vec2(1.0f
/ screenWidth
, 1.0f
/ screenHeight
);
99 const Vec2 partSz
= Vec2(barSz
, 0.9f
/ container
.GetMaxParticles());
100 const Vec2 contLoc
= Vec2(barIdx
* barGap
+ barSz
* 3.0f
+ startPos
, startPos
);
101 const float off
= barSz
* 0.5f
;
107 const Vec2 instSz
= Vec2(barSz
, 0.9f
/ numInstances
);
108 const Vec2 instLoc
= Vec2(barIdx
* barGap
+ startPos
, startPos
);
110 for (uint i
= 0; i
< numInstances
; ++i
)
114 box
.max
.x
= box
.min
.x
+ std::max(instSz
.x
, pixSz
.x
);
115 box
.max
.y
= box
.min
.y
+ std::max(instSz
.y
- pixSz
.y
, pixSz
.y
);
116 ColorF color
= ColorF(0.0f
, 0.5f
, 1.0f
);
117 pRenderAux
->DrawAABB(box
, true, ColorB(color
), eBBD_Faceted
);
124 for (auto particleId
: context
.GetUpdateRange())
128 box
.min
.x
= contLoc
.x
;
129 box
.min
.y
= contLoc
.y
+ partSz
.y
* particleId
;
130 box
.max
.x
= box
.min
.x
+ std::max(partSz
.x
, pixSz
.x
);
131 box
.max
.y
= box
.min
.y
+ std::max(partSz
.y
- pixSz
.y
, pixSz
.y
);
132 ColorB color
= black
;
133 const float age
= normAges
.Load(particleId
);
135 color
= ColorB(ColorF(age
, 1.0f
- age
, 0.0f
));
136 pRenderAux
->DrawAABB(box
, true, color
, eBBD_Faceted
);
139 if (pRuntime
->IsChild())
141 const CParticleContainer
& parentContainer
= pRuntime
->GetParentContainer();
142 const Vec2 parentPartSz
= Vec2(barSz
, 0.9f
/ parentContainer
.GetMaxParticles());
143 const Vec2 parentContLoc
= Vec2((emitterBarIdx
/*+ params.m_parentId*/) * barGap
+ barSz
* 3.0f
+ startPos
, startPos
);
146 for (auto particleId
: context
.GetUpdateRange())
148 const TParticleId parentId
= parentIds
.Load(particleId
);
149 if (parentId
== gInvalidId
)
151 Vec2 from
= contLoc
+ partSz
* 0.5f
+ Vec2(-off
, partSz
.y
* particleId
);
152 Vec2 to
= parentContLoc
+ parentPartSz
* 0.5f
+ Vec2(off
, parentPartSz
.y
* parentId
);
153 pRenderAux
->DrawLine(from
, lightOrange
, to
, black
, 1.0f
);
157 IRenderAuxText::Draw2dLabel(
158 screenSz
.x
* (barIdx
* barGap
+ startPos
),
159 screenSz
.y
* 0.95f
, 1.0f
, whiteF
, false,
160 "%s", pRuntime
->GetComponent()->GetName());
162 pRenderAux
->SetRenderFlags(prevFlags
);
165 void DebugDrawComponentCollisions(CParticleComponentRuntime
* pRuntime
)
167 IRenderAuxGeom
* pRenderAux
= gEnv
->pRenderer
->GetIRenderAuxGeom();
168 SAuxGeomRenderFlags prevFlags
= pRenderAux
->GetRenderFlags();
169 SAuxGeomRenderFlags curFlags
= prevFlags
;
170 curFlags
.SetMode2D3DFlag(e_Mode3D
);
171 curFlags
.SetDepthTestFlag(e_DepthTestOn
);
172 curFlags
.SetDepthWriteFlag(e_DepthWriteOn
);
173 pRenderAux
->SetRenderFlags(curFlags
);
175 const auto context
= SUpdateContext(pRuntime
);
176 const CParticleContainer
& container
= pRuntime
->GetContainer();
177 if (!container
.HasData(EPDT_ContactPoint
))
179 const TIStream
<SContactPoint
> contactPoints
= container
.IStream(EPDT_ContactPoint
);
181 for (auto particleId
: context
.GetUpdateRange())
183 SContactPoint contact
= contactPoints
.Load(particleId
);
185 if (contact
.m_totalCollisions
== 0)
188 ColorB color
= ColorB(0, 0, 0);
189 if (contact
.m_state
.ignore
)
190 color
= ColorB(128, 128, 128);
191 else if (contact
.m_state
.sliding
)
192 color
= ColorB(255, 128, 64);
194 color
= ColorB(64, 128, 255);
196 pRenderAux
->DrawSphere(contact
.m_point
, 0.05f
, color
);
197 pRenderAux
->DrawLine(
198 contact
.m_point
, color
,
199 contact
.m_point
+ contact
.m_normal
*0.25f
, color
);
202 pRenderAux
->SetRenderFlags(prevFlags
);
205 #if CRY_PLATFORM_SSE2
207 void DrawLineSSE(IRenderAuxGeom
* pRenderAux
, __m128 x
, __m128 y
, ColorB color
)
210 pRenderAux
->DrawLine(
211 Vec2(x
.m128_f32
[3], (1.0f
- y
.m128_f32
[3]) * 0.9f
+ 0.05f
), color
,
212 Vec2(x
.m128_f32
[2], (1.0f
- y
.m128_f32
[2]) * 0.9f
+ 0.05f
), color
, 1.0f
);
213 pRenderAux
->DrawLine(
214 Vec2(x
.m128_f32
[2], (1.0f
- y
.m128_f32
[2]) * 0.9f
+ 0.05f
), color
,
215 Vec2(x
.m128_f32
[1], (1.0f
- y
.m128_f32
[1]) * 0.9f
+ 0.05f
), color
, 1.0f
);
216 pRenderAux
->DrawLine(
217 Vec2(x
.m128_f32
[1], (1.0f
- y
.m128_f32
[1]) * 0.9f
+ 0.05f
), color
,
218 Vec2(x
.m128_f32
[0], (1.0f
- y
.m128_f32
[0]) * 0.9f
+ 0.05f
), color
, 1.0f
);
224 void DebugOptSpline()
227 typedef spline::OptSpline
<float> TOptSplineF
;
229 static bool init
= false;
230 static TOptSplineF optSpline
;
231 static CParticleSpline particleSpline
;
236 CParticleSpline::CSourceSpline source
;
237 CParticleSpline::CSourceSpline::key_type key
;
240 (SPLINE_KEY_TANGENT_LINEAR
<< SPLINE_KEY_TANGENT_IN_SHIFT
) |
241 (SPLINE_KEY_TANGENT_NONE
<< SPLINE_KEY_TANGENT_OUT_SHIFT
);
244 source
.insert_key(key
);
247 source
.insert_key(key
);
250 source
.insert_key(key
);
253 source
.insert_key(key
);
256 optSpline
.from_source(source
);
257 particleSpline
.FromSpline(source
);
260 IRenderer
* pRender
= gEnv
->pRenderer
;
261 IRenderAuxGeom
* pRenderAux
= gEnv
->pRenderer
->GetIRenderAuxGeom();
262 SAuxGeomRenderFlags prevFlags
= pRenderAux
->GetRenderFlags();
263 SAuxGeomRenderFlags curFlags
= prevFlags
;
264 Vec2 screenSz
= Vec2(float(gEnv
->pRenderer
->GetWidth()), float(gEnv
->pRenderer
->GetHeight()));
265 curFlags
.SetMode2D3DFlag(e_Mode2D
);
266 pRenderAux
->SetRenderFlags(curFlags
);
268 const int numSamples
= 100;
269 const float sampleSz
= 1.0f
/ numSamples
;
272 optSpline
.interpolate(0.0f
, prevValue
);
273 for (float t
= sampleSz
; t
<= 1.0f
; t
+= sampleSz
)
276 optSpline
.interpolate(t
, curValue
);
277 pRenderAux
->DrawLine(
278 Vec2(t
- sampleSz
, (1.0f
- prevValue
) * 0.9f
+ 0.05f
), red
,
279 Vec2(t
, (1.0f
- curValue
) * 0.9f
+ 0.05f
), red
, 1.0f
);
280 prevValue
= curValue
;
283 prevValue
= particleSpline
.Interpolate(0.0f
);
284 for (float t
= sampleSz
; t
<= 1.0f
; t
+= sampleSz
)
287 curValue
= particleSpline
.Interpolate(t
);
288 pRenderAux
->DrawLine(
289 Vec2(t
- sampleSz
, (1.0f
- prevValue
) * 0.9f
+ 0.05f
), lightOrange
,
290 Vec2(t
, (1.0f
- curValue
) * 0.9f
+ 0.05f
), lightOrange
, 1.0f
);
291 prevValue
= curValue
;
294 const ColorB
blue(128, 198, 255);
295 for (float t
= 0.0f
; t
< 1.0f
; t
+= sampleSz
* 4.0f
)
297 __m128 timeSSE
= _mm_set_ps(t
, t
+ sampleSz
, t
+ sampleSz
* 2.0f
, t
+ sampleSz
* 3.0f
);
298 __m128 curValueSSE
= particleSpline
.Interpolate(timeSSE
);
299 DrawLineSSE(pRenderAux
, timeSSE
, curValueSSE
, blue
);
302 pRenderAux
->SetRenderFlags(prevFlags
);
308 void DebugParticleSystem(const TParticleEmitters
& activeEmitters
)
312 CVars
* pCVars
= static_cast<C3DEngine
*>(gEnv
->p3DEngine
)->GetCVars();
313 const bool debugContainers
= (pCVars
->e_ParticlesDebug
& AlphaBit('c')) != 0;
314 const bool debugCollisions
= (pCVars
->e_ParticlesDebug
& AlphaBit('k')) != 0;
316 if (debugContainers
|| debugCollisions
)
318 IRenderer
* pRender
= gEnv
->pRenderer
;
319 IRenderAuxGeom
* pRenderAux
= gEnv
->pRenderer
->GetIRenderAuxGeom();
321 size_t emitterBarIdx
= 0;
323 for (CParticleEmitter
* pEmitter
: activeEmitters
)
325 CParticleEffect
* pEffect
= pEmitter
->GetCEffect();
326 for (auto pRuntime
: pEmitter
->GetRuntimes())
328 auto pComponentRuntime
= pRuntime
->GetCpuRuntime();
329 if (!pComponentRuntime
)
331 if (!pComponentRuntime
->GetComponent()->IsEnabled())
334 DebugDrawComponentRuntime(pComponentRuntime
, emitterBarIdx
, barIdx
++);
336 DebugDrawComponentCollisions(pComponentRuntime
);
338 emitterBarIdx
= barIdx
;
345 void DebugParticleSystem(const TParticleEmitters
& activeEmitters
) {}