diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 9e7983145..c14b6dfd8 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -374,14 +374,7 @@ namespace FlaxEditor.Viewport // Draw selected objects debug shapes and visuals if (DrawDebugDraw && (renderContext.View.Flags & ViewFlags.DebugDraw) == ViewFlags.DebugDraw) { - unsafe - { - fixed (IntPtr* actors = _debugDrawData.ActorsPtrs) - { - DebugDraw.DrawActors(new IntPtr(actors), _debugDrawData.ActorsCount, true); - } - } - + _debugDrawData.DrawActors(); DebugDraw.Draw(ref renderContext, target.View(), targetDepth.View(), true); } } diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 2efe7c95f..8b508eedf 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -643,14 +643,7 @@ namespace FlaxEditor.Viewport if (selectedParents[i].IsActiveInHierarchy) selectedParents[i].OnDebugDraw(_debugDrawData); } - - unsafe - { - fixed (IntPtr* actors = _debugDrawData.ActorsPtrs) - { - DebugDraw.DrawActors(new IntPtr(actors), _debugDrawData.ActorsCount, false); - } - } + _debugDrawData.DrawActors(); // Debug draw all actors in prefab and collect actors var view = Task.View; diff --git a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs index 408b7161f..74c7c435b 100644 --- a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs +++ b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs @@ -246,6 +246,14 @@ namespace FlaxEditor.Viewport.Previews } } + /// + protected override void OnDebugDraw(GPUContext context, ref RenderContext renderContext) + { + base.OnDebugDraw(context, ref renderContext); + + _previewEffect.OnDebugDraw(); + } + /// public override void Draw() { @@ -295,7 +303,8 @@ namespace FlaxEditor.Viewport.Previews /// public override void OnDestroy() { - // Cleanup objects + if (IsDisposing) + return; _previewEffect.ParticleSystem = null; Object.Destroy(ref _previewEffect); Object.Destroy(ref _boundsModel); diff --git a/Source/Editor/ViewportDebugDrawData.cs b/Source/Editor/ViewportDebugDrawData.cs index 7913e0287..7b5bee95c 100644 --- a/Source/Editor/ViewportDebugDrawData.cs +++ b/Source/Editor/ViewportDebugDrawData.cs @@ -88,6 +88,18 @@ namespace FlaxEditor } } + /// + /// Draws the collected actors via . + /// + /// True if draw all loaded scenes too, otherwise will draw only provided actors. + public unsafe void DrawActors(bool drawScenes = false) + { + fixed (IntPtr* actors = ActorsPtrs) + { + DebugDraw.DrawActors(new IntPtr(actors), _actors.Count, drawScenes); + } + } + /// /// Called when task calls event. /// diff --git a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs index 6513ac9e0..0c8653f5b 100644 --- a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs +++ b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs @@ -113,8 +113,55 @@ namespace FlaxEditor.Windows.Assets } } + private sealed class LayoutTabProxy + { + [EditorDisplay("Layout"), CustomEditor(typeof(Editor)), NoSerialize] + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public ParticleEmitterWindow Window; + + private class Editor : CustomEditor + { + public override DisplayStyle Style => DisplayStyle.InlineIntoParent; + + public override void Initialize(LayoutElementsContainer layout) + { + var window = (ParticleEmitterWindow)Values[0]; + var emitter = window.Preview.Emitter; + if (emitter == null || !emitter.IsLoaded) + return; + var attributes = emitter.Layout; + var size = 0; + var height = 14; + foreach (var attribute in attributes) + { + layout.Label($" - {GetAttributeType(attribute.Format)} {attribute.Name}").Label.Height = height; + size += PixelFormatExtensions.SizeInBytes(attribute.Format); + } + var capacity = 0; + if (window.Surface != null && window.Surface.RootNode != null && window.Surface.RootNode.Values.Length > 0) + capacity = (int)window.Surface.RootNode.Values[0]; + layout.Space(10); + layout.Label($"Particle size: {size} bytes\nParticle buffer size: {Utilities.Utils.FormatBytesCount((ulong)(size * capacity))}").Label.Height = height * 2; + } + + private static string GetAttributeType(PixelFormat format) + { + switch (format) + { + case PixelFormat.R32_Float: return "float"; + case PixelFormat.R32G32_Float: return "Float2"; + case PixelFormat.R32G32B32_Float: return "Float3"; + case PixelFormat.R32G32B32A32_Float: return "Float4"; + case PixelFormat.R32_SInt: return "int"; + case PixelFormat.R32_UInt: return "uint"; + default: return format.ToString(); + } + } + } + } + private readonly PropertiesProxy _properties; - private Tab _previewTab; + private Tab _previewTab, _layoutTab; private ToolStripButton _showSourceCodeButton; /// @@ -127,18 +174,22 @@ namespace FlaxEditor.Windows.Assets PlaySimulation = true, Parent = _split2.Panel1 }; + _preview.PreviewActor.ShowDebugDraw = true; + _preview.ShowDebugDraw = true; // Asset properties proxy _properties = new PropertiesProxy(); // Preview properties editor _previewTab = new Tab("Preview"); - _previewTab.Presenter.Select(new PreviewProxy - { - Window = this, - }); + _previewTab.Presenter.Select(new PreviewProxy { Window = this }); _tabs.AddTab(_previewTab); + // Particle data layout + _layoutTab = new Tab("Layout"); + _layoutTab.Presenter.Select(new LayoutTabProxy { Window = this }); + _tabs.AddTab(_layoutTab); + // Surface _surface = new ParticleEmitterSurface(this, Save, _undo) { @@ -237,6 +288,7 @@ namespace FlaxEditor.Windows.Assets _asset.WaitForLoaded(); _preview.PreviewActor.ResetSimulation(); _previewTab.Presenter.BuildLayoutOnUpdate(); + _layoutTab.Presenter.BuildLayoutOnUpdate(); } } @@ -253,6 +305,7 @@ namespace FlaxEditor.Windows.Assets // Init asset properties and parameters proxy _properties.OnLoad(this); _previewTab.Presenter.BuildLayoutOnUpdate(); + _layoutTab.Presenter.BuildLayoutOnUpdate(); return false; } diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index e05f0d2db..acb2deda3 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -510,13 +510,7 @@ namespace FlaxEditor.Windows selectedParents[i].OnDebugDraw(drawDebugData); } } - unsafe - { - fixed (IntPtr* actors = drawDebugData.ActorsPtrs) - { - DebugDraw.DrawActors(new IntPtr(actors), drawDebugData.ActorsCount, true); - } - } + drawDebugData.DrawActors(true); } DebugDraw.Draw(ref renderContext, task.OutputView); diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.ParticleModules.cpp b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.ParticleModules.cpp index ad6381809..bb1e977e4 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.ParticleModules.cpp +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.ParticleModules.cpp @@ -2,8 +2,16 @@ #include "ParticleEmitterGraph.CPU.h" #include "Engine/Core/Random.h" +#include "Engine/Core/Math/Vector2.h" +#include "Engine/Core/Math/Vector3.h" +#include "Engine/Core/Math/Vector4.h" +#include "Engine/Core/Math/Matrix.h" +#include "Engine/Core/Math/Quaternion.h" +#include "Engine/Core/Math/BoundingBox.h" +#include "Engine/Core/Math/BoundingSphere.h" +#include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Utilities/Noise.h" -#include "Engine/Core/Types/CommonValue.h" +#include "Engine/Debug/DebugDraw.h" // ReSharper disable CppCStyleCast // ReSharper disable CppClangTidyClangDiagnosticCastAlign @@ -1468,3 +1476,89 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode* #undef COLLISION_LOGIC } } + +#if USE_EDITOR + +void ParticleEmitterGraphCPUExecutor::DebugDrawModule(ParticleEmitterGraphCPUNode* node, const Transform& transform) +{ + // Skip modules that rely on particle data + if (node->UsePerParticleDataResolve()) + return; + + const Color color = Color::White; + switch (node->TypeID) + { + case 202: // Position (sphere surface) + case 211: // Position (sphere volume) + { + const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2)); + const float radius = (float)GetValue(node->GetBox(1), 3); + DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(center, radius), color, 0.0f, true); + break; + } + case 203: // Position (plane) + { + const Float3 center = (Float3)GetValue(node->GetBox(0), 2); + const Float2 size = (Float2)GetValue(node->GetBox(1), 3); + const Float3 halfExtent = Float3(size.X * 0.5f, 0.0f, size.Y * 0.5f); + OrientedBoundingBox box(halfExtent, Transform(center)); + box.Transform(transform); + DEBUG_DRAW_WIRE_BOX(box, color, 0.0f, true); + break; + } + case 204: // Position (circle) + case 205: // Position (disc) + { + const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2)); + const float radius = (float)GetValue(node->GetBox(1), 3); + DEBUG_DRAW_WIRE_CYLINDER(center, transform.Orientation * Quaternion::Euler(90, 0, 0), radius, 0.0f, color, 0.0f, true); + break; + } + case 206: // Position (box surface) + case 207: // Position (box volume) + { + const Float3 center = (Float3)GetValue(node->GetBox(0), 2); + const Float3 size = (Float3)GetValue(node->GetBox(1), 3); + OrientedBoundingBox box(size * 0.5f, Transform(center)); + box.Transform(transform); + DEBUG_DRAW_WIRE_BOX(box, color, 0.0f, true); + break; + } + // Position (cylinder) + case 208: + { + const float height = (float)GetValue(node->GetBox(2), 4); + const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2) + Float3(0, 0, height * 0.5f)); + const float radius = (float)GetValue(node->GetBox(1), 3); + DEBUG_DRAW_WIRE_CYLINDER(center, transform.Orientation * Quaternion::Euler(90, 0, 0), radius, height, color, 0.0f, true); + break; + } + // Position (line) + case 209: + { + const Float3 start = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2)); + const Float3 end = transform.LocalToWorld((Float3)GetValue(node->GetBox(1), 3)); + DEBUG_DRAW_LINE(start, end, color, 0.0f, true); + break; + } + // Position (torus) + case 210: + { + const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2)); + const float radius = Math::Max((float)GetValue(node->GetBox(1), 3), ZeroTolerance); + const float thickness = (float)GetValue(node->GetBox(2), 4); + DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(center, radius + thickness), color, 0.0f, true); + break; + } + + // Position (spiral) + case 214: + { + const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2)); + DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(center, 5.0f), color, 0.0f, true); + break; + } + } +} + +#endif diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp index 39f87d561..bdfdf1956 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp @@ -7,6 +7,7 @@ #include "Engine/Particles/ParticleEffect.h" #include "Engine/Engine/Time.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Debug/DebugDraw.h" ThreadLocal ParticleEmitterGraphCPUExecutor::Context; @@ -423,6 +424,23 @@ void ParticleEmitterGraphCPUExecutor::Draw(ParticleEmitter* emitter, ParticleEff } } +#if USE_EDITOR + +void ParticleEmitterGraphCPUExecutor::DrawDebug(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data) +{ + // Prepare graph data + Init(emitter, effect, data); + Transform transform = emitter->SimulationSpace == ParticlesSimulationSpace::Local ? effect->GetTransform() : Transform::Identity; + + // Draw modules + for (auto module : emitter->Graph.SpawnModules) + DebugDrawModule(module, transform); + for (auto module : emitter->Graph.InitModules) + DebugDrawModule(module, transform); +} + +#endif + void ParticleEmitterGraphCPUExecutor::Update(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, float dt, bool canSpawn) { // Prepare data diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h index a31917cf8..82b7a1bef 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h @@ -162,6 +162,16 @@ public: /// The effect transform matrix. void Draw(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, RenderContext& renderContext, Matrix& transform); +#if USE_EDITOR + /// + /// Draws the particles debug shapes. + /// + /// The owning emitter. + /// The instance effect. + /// The instance data. + void DrawDebug(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data); +#endif + /// /// Updates the particles simulation (the CPU simulation). /// @@ -195,6 +205,9 @@ private: int32 ProcessSpawnModule(int32 index); void ProcessModule(ParticleEmitterGraphCPUNode* node, int32 particlesStart, int32 particlesEnd); +#if USE_EDITOR + void DebugDrawModule(ParticleEmitterGraphCPUNode* node, const Transform& transform); +#endif FORCE_INLINE Value GetValue(Box* box, int32 defaultValueBoxIndex) { diff --git a/Source/Engine/Particles/ParticleEffect.cpp b/Source/Engine/Particles/ParticleEffect.cpp index 93ccef55c..3f1ac7055 100644 --- a/Source/Engine/Particles/ParticleEffect.cpp +++ b/Source/Engine/Particles/ParticleEffect.cpp @@ -587,10 +587,19 @@ void ParticleEffect::OnDebugDrawSelected() { DEBUG_DRAW_WIRE_BOX(_box, Color::Violet * 0.7f, 0, true); - // Base Actor::OnDebugDrawSelected(); } +void ParticleEffect::OnDebugDraw() +{ + if (ShowDebugDraw) + { + Particles::DebugDraw(this); + } + + Actor::OnDebugDraw(); +} + #endif void ParticleEffect::OnLayerChanged() diff --git a/Source/Engine/Particles/ParticleEffect.h b/Source/Engine/Particles/ParticleEffect.h index 8529732dd..2964012f6 100644 --- a/Source/Engine/Particles/ParticleEffect.h +++ b/Source/Engine/Particles/ParticleEffect.h @@ -244,6 +244,13 @@ public: API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), EditorOrder(80), DefaultValue(0)") int8 SortOrder = 0; +#if USE_EDITOR + /// + /// If checked, the particle emitter debug shapes will be shawn during debug drawing. This includes particle spawn location shapes display. + /// + API_FIELD(Attributes = "EditorDisplay(\"Particle Effect\"), EditorOrder(200)") bool ShowDebugDraw = false; +#endif + public: /// /// Gets the effect parameters collection. Those parameters are instanced from the that contains a linear list of emitters and every emitter has a list of own parameters. @@ -399,6 +406,7 @@ public: void Draw(RenderContext& renderContext) override; #if USE_EDITOR void OnDebugDrawSelected() override; + void OnDebugDraw() override; #endif void OnLayerChanged() override; void Serialize(SerializeStream& stream, const void* otherObj) override; diff --git a/Source/Engine/Particles/ParticleEmitter.cpp b/Source/Engine/Particles/ParticleEmitter.cpp index 3e1847b67..9991692c2 100644 --- a/Source/Engine/Particles/ParticleEmitter.cpp +++ b/Source/Engine/Particles/ParticleEmitter.cpp @@ -522,4 +522,39 @@ bool ParticleEmitter::HasShaderCode() const return false; } +Array ParticleEmitter::GetLayout() const +{ + Array result; + ScopeLock lock(Locker); + result.Resize(Graph.Layout.Attributes.Count()); + for (int32 i = 0; i < result.Count(); i++) + { + auto& dst = result[i]; + const auto& src = Graph.Layout.Attributes[i]; + dst.Name = src.Name; + switch (src.ValueType) + { + case ParticleAttribute::ValueTypes::Float: + dst.Format = PixelFormat::R32_Float; + break; + case ParticleAttribute::ValueTypes::Float2: + dst.Format = PixelFormat::R32G32_Float; + break; + case ParticleAttribute::ValueTypes::Float3: + dst.Format = PixelFormat::R32G32B32_Float; + break; + case ParticleAttribute::ValueTypes::Float4: + dst.Format = PixelFormat::R32G32B32A32_Float; + break; + case ParticleAttribute::ValueTypes::Int: + dst.Format = PixelFormat::R32_SInt; + break; + case ParticleAttribute::ValueTypes::Uint: + dst.Format = PixelFormat::R32_UInt; + break; + } + } + return result; +} + #endif diff --git a/Source/Engine/Particles/ParticleEmitter.h b/Source/Engine/Particles/ParticleEmitter.h index 1398de5db..23ee83e21 100644 --- a/Source/Engine/Particles/ParticleEmitter.h +++ b/Source/Engine/Particles/ParticleEmitter.h @@ -177,10 +177,16 @@ public: void GetReferences(Array& assets, Array& files) const override; bool Save(const StringView& path = StringView::Empty) override; - /// - /// Checks if the particle emitter has valid shader code present. - /// - API_PROPERTY() bool HasShaderCode() const; + API_STRUCT(Internal) struct Attribute + { + DECLARE_SCRIPTING_TYPE_MINIMAL(Attribute); + API_FIELD() PixelFormat Format; + API_FIELD() String Name; + }; + +private: + API_PROPERTY(Internal) bool HasShaderCode() const; + API_PROPERTY(Internal) Array GetLayout() const; #endif protected: diff --git a/Source/Engine/Particles/Particles.cpp b/Source/Engine/Particles/Particles.cpp index 3cf25eec6..b8dce728a 100644 --- a/Source/Engine/Particles/Particles.cpp +++ b/Source/Engine/Particles/Particles.cpp @@ -936,6 +936,7 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe if (drawModes == DrawPass::None || SpriteRenderer.Init()) return; PROFILE_MEM(Particles); + ConcurrentSystemLocker::ReadScope systemScope(SystemLocker); Matrix worlds[2]; Matrix::Translation(-renderContext.View.Origin, worlds[0]); // World renderContext.View.GetWorldMatrix(effect->GetTransform(), worlds[1]); // Local @@ -1068,6 +1069,28 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe } } +#if USE_EDITOR + +void Particles::DebugDraw(ParticleEffect* effect) +{ + PROFILE_CPU_NAMED("Particles.DrawDebug"); + ConcurrentSystemLocker::ReadScope systemScope(SystemLocker); + + // Draw all emitters + for (auto& emitterData : effect->Instance.Emitters) + { + const auto buffer = emitterData.Buffer; + if (!buffer) + continue; + auto emitter = buffer->Emitter; + if (!emitter || !emitter->IsLoaded()) + continue; + emitter->GraphExecutorCPU.DrawDebug(emitter, effect, emitterData); + } +} + +#endif + #if COMPILE_WITH_GPU_PARTICLES void UpdateGPU(RenderTask* task, GPUContext* context) diff --git a/Source/Engine/Particles/Particles.h b/Source/Engine/Particles/Particles.h index 69d0f9dab..77f651cfa 100644 --- a/Source/Engine/Particles/Particles.h +++ b/Source/Engine/Particles/Particles.h @@ -52,6 +52,14 @@ public: /// The owning actor. static void DrawParticles(RenderContext& renderContext, ParticleEffect* effect); +#if USE_EDITOR + /// + /// Draws the particles debug shapes. + /// + /// The owning actor. + static void DebugDraw(ParticleEffect* effect); +#endif + public: /// /// Enables or disables particle buffer pooling. diff --git a/Source/Engine/Particles/ParticlesData.cpp b/Source/Engine/Particles/ParticlesData.cpp index 10988fd34..9b5a26246 100644 --- a/Source/Engine/Particles/ParticlesData.cpp +++ b/Source/Engine/Particles/ParticlesData.cpp @@ -7,6 +7,89 @@ #include "Engine/Graphics/DynamicBuffer.h" #include "Engine/Profiler/ProfilerMemory.h" +int32 ParticleAttribute::GetSize() const +{ + switch (ValueType) + { + case ValueTypes::Float2: + return 8; + case ValueTypes::Float3: + return 12; + case ValueTypes::Float4: + return 16; + case ValueTypes::Float: + case ValueTypes::Int: + case ValueTypes::Uint: + return 4; + default: + return 0; + } +} + +void ParticleLayout::Clear() +{ + Size = 0; + Attributes.Clear(); +} + +void ParticleLayout::UpdateLayout() +{ + Size = 0; + for (int32 i = 0; i < Attributes.Count(); i++) + { + Attributes[i].Offset = Size; + Size += Attributes[i].GetSize(); + } +} + +int32 ParticleLayout::FindAttribute(const StringView& name) const +{ + for (int32 i = 0; i < Attributes.Count(); i++) + { + if (name == Attributes[i].Name) + return i; + } + return -1; +} + +int32 ParticleLayout::FindAttribute(const StringView& name, ParticleAttribute::ValueTypes valueType) const +{ + for (int32 i = 0; i < Attributes.Count(); i++) + { + if (Attributes[i].ValueType == valueType && name == Attributes[i].Name) + return i; + } + return -1; +} + +int32 ParticleLayout::FindAttributeOffset(const StringView& name, int32 fallbackValue) const +{ + for (int32 i = 0; i < Attributes.Count(); i++) + { + if (name == Attributes[i].Name) + return Attributes[i].Offset; + } + return fallbackValue; +} + +int32 ParticleLayout::FindAttributeOffset(const StringView& name, ParticleAttribute::ValueTypes valueType, int32 fallbackValue) const +{ + for (int32 i = 0; i < Attributes.Count(); i++) + { + if (Attributes[i].ValueType == valueType && name == Attributes[i].Name) + return Attributes[i].Offset; + } + return fallbackValue; +} + +int32 ParticleLayout::AddAttribute(const StringView& name, ParticleAttribute::ValueTypes valueType) +{ + auto& a = Attributes.AddOne(); + a.Name = String(*name, name.Length()); + a.ValueType = valueType; + return Attributes.Count() - 1; +} + ParticleBuffer::ParticleBuffer() { } diff --git a/Source/Engine/Particles/ParticlesData.h b/Source/Engine/Particles/ParticlesData.h index 2d81d70f0..53f63826f 100644 --- a/Source/Engine/Particles/ParticlesData.h +++ b/Source/Engine/Particles/ParticlesData.h @@ -52,25 +52,7 @@ struct ParticleAttribute /// /// Gets the size of the attribute (in bytes). /// - /// The size (in bytes). - int32 GetSize() const - { - switch (ValueType) - { - case ValueTypes::Float2: - return 8; - case ValueTypes::Float3: - return 12; - case ValueTypes::Float4: - return 16; - case ValueTypes::Float: - case ValueTypes::Int: - case ValueTypes::Uint: - return 4; - default: - return 0; - } - } + int32 GetSize() const; }; /// @@ -93,41 +75,19 @@ public: /// /// Clears the layout data. /// - void Clear() - { - Size = 0; - Attributes.Clear(); - } + void Clear(); /// /// Updates the attributes layout (calculates offset) and updates the total size of the layout. /// - void UpdateLayout() - { - Size = 0; - for (int32 i = 0; i < Attributes.Count(); i++) - { - Attributes[i].Offset = Size; - Size += Attributes[i].GetSize(); - } - } + void UpdateLayout(); /// /// Finds the attribute by the name. /// /// The name. /// The attribute index or -1 if cannot find it. - int32 FindAttribute(const StringView& name) const - { - for (int32 i = 0; i < Attributes.Count(); i++) - { - if (name == Attributes[i].Name) - { - return i; - } - } - return -1; - } + int32 FindAttribute(const StringView& name) const; /// /// Finds the attribute by the name and type. @@ -135,17 +95,7 @@ public: /// The name. /// The type. /// The attribute index or -1 if cannot find it. - int32 FindAttribute(const StringView& name, ParticleAttribute::ValueTypes valueType) const - { - for (int32 i = 0; i < Attributes.Count(); i++) - { - if (Attributes[i].ValueType == valueType && name == Attributes[i].Name) - { - return i; - } - } - return -1; - } + int32 FindAttribute(const StringView& name, ParticleAttribute::ValueTypes valueType) const; /// /// Finds the attribute offset by the name. @@ -153,17 +103,7 @@ public: /// The name. /// The fallback value to return if attribute is missing. /// The attribute offset or fallback value if cannot find it. - int32 FindAttributeOffset(const StringView& name, int32 fallbackValue = 0) const - { - for (int32 i = 0; i < Attributes.Count(); i++) - { - if (name == Attributes[i].Name) - { - return Attributes[i].Offset; - } - } - return fallbackValue; - } + int32 FindAttributeOffset(const StringView& name, int32 fallbackValue = 0) const; /// /// Finds the attribute offset by the name. @@ -172,17 +112,7 @@ public: /// The type. /// The fallback value to return if attribute is missing. /// The attribute offset or fallback value if cannot find it. - int32 FindAttributeOffset(const StringView& name, ParticleAttribute::ValueTypes valueType, int32 fallbackValue = 0) const - { - for (int32 i = 0; i < Attributes.Count(); i++) - { - if (Attributes[i].ValueType == valueType && name == Attributes[i].Name) - { - return Attributes[i].Offset; - } - } - return fallbackValue; - } + int32 FindAttributeOffset(const StringView& name, ParticleAttribute::ValueTypes valueType, int32 fallbackValue = 0) const; /// /// Gets the attribute offset by the attribute index. @@ -201,13 +131,7 @@ public: /// The name. /// The value type. /// The attribute index or -1 if cannot find it. - int32 AddAttribute(const StringView& name, ParticleAttribute::ValueTypes valueType) - { - auto& a = Attributes.AddOne(); - a.Name = String(*name, name.Length()); - a.ValueType = valueType; - return Attributes.Count() - 1; - } + int32 AddAttribute(const StringView& name, ParticleAttribute::ValueTypes valueType); }; ///