text: #include "stdafx.h"
  #include "EmitterWindow.h"
  #include "Editor.h"
  
  #include <string>
  
  using namespace wi::ecs;
  using namespace wi::scene;
  
  void EmitterWindow::Create(EditorComponent* editor)
  {
  	wi::gui::Window::Create("Emitter Window");
  	SetSize(XMFLOAT2(680, 720));
  
  	float x = 200;
  	float y = 5;
  	float itemheight = 18;
  	float step = itemheight + 2;
  
  
  	emitterNameField.Create("EmitterName");
  	emitterNameField.SetPos(XMFLOAT2(x, y += step));
  	emitterNameField.SetSize(XMFLOAT2(300, itemheight));
  	emitterNameField.OnInputAccepted([=](wi::gui::EventArgs args) {
  		NameComponent* name = wi::scene::GetScene().names.GetComponent(entity);
  		if (name != nullptr)
  		{
  			*name = args.sValue;
  
  			editor->RefreshSceneGraphView();
  		}
  	});
  	AddWidget(&emitterNameField);
  
  	addButton.Create("Add Emitter");
  	addButton.SetPos(XMFLOAT2(x, y += step));
  	addButton.SetSize(XMFLOAT2(150, itemheight));
  	addButton.OnClick([=](wi::gui::EventArgs args) {
  		Scene& scene = wi::scene::GetScene();
  		Entity entity = scene.Entity_CreateEmitter("editorEmitter");
  
  		wi::Archive& archive = editor->AdvanceHistory();
  		archive << EditorComponent::HISTORYOP_ADD;
  		editor->RecordSelection(archive);
  
  		editor->ClearSelected();
  		editor->AddSelected(entity);
  
  		editor->RecordSelection(archive);
  		editor->RecordAddedEntity(archive, entity);
  
  		editor->RefreshSceneGraphView();
  		SetEntity(entity);
  	});
  	addButton.SetTooltip("Add new emitter particle system.");
  	AddWidget(&addButton);
  
  	restartButton.Create("Restart Emitter");
  	restartButton.SetPos(XMFLOAT2(x + 160, y));
  	restartButton.SetSize(XMFLOAT2(150, itemheight));
  	restartButton.OnClick([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->Restart();
  		}
  	});
  	restartButton.SetTooltip("Restart particle system emitter");
  	AddWidget(&restartButton);
  
  	meshComboBox.Create("Mesh: ");
  	meshComboBox.SetSize(XMFLOAT2(300, itemheight));
  	meshComboBox.SetPos(XMFLOAT2(x, y += step));
  	meshComboBox.SetEnabled(false);
  	meshComboBox.OnSelect([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			if (args.iValue == 0)
  			{
  				emitter->meshID = INVALID_ENTITY;
  			}
  			else
  			{
  				Scene& scene = wi::scene::GetScene();
  				emitter->meshID = scene.meshes.GetEntity(args.iValue - 1);
  			}
  		}
  	});
  	meshComboBox.SetTooltip("Choose an mesh that particles will be emitted from...");
  	AddWidget(&meshComboBox);
  
  	shaderTypeComboBox.Create("ShaderType: ");
  	shaderTypeComboBox.SetPos(XMFLOAT2(x, y += step));
  	shaderTypeComboBox.SetSize(XMFLOAT2(300, itemheight));
  	shaderTypeComboBox.AddItem("SOFT");
  	shaderTypeComboBox.AddItem("SOFT + DISTORTION");
  	shaderTypeComboBox.AddItem("SIMPLEST");
  	shaderTypeComboBox.AddItem("SOFT + LIGHTING");
  	shaderTypeComboBox.OnSelect([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->shaderType = (wi::EmittedParticleSystem::PARTICLESHADERTYPE)args.iValue;
  		}
  	});
  	shaderTypeComboBox.SetEnabled(false);
  	shaderTypeComboBox.SetTooltip("Choose a shader type for the particles. This is responsible of how they will be rendered.");
  	AddWidget(&shaderTypeComboBox);
  
  
  	sortCheckBox.Create("Sorting Enabled: ");
  	sortCheckBox.SetPos(XMFLOAT2(x, y += step));
  	sortCheckBox.SetSize(XMFLOAT2(itemheight, itemheight));
  	sortCheckBox.OnClick([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SetSorted(args.bValue);
  		}
  	});
  	sortCheckBox.SetCheck(false);
  	sortCheckBox.SetTooltip("Enable sorting of the particles. This might slow down performance.");
  	AddWidget(&sortCheckBox);
  
  
  	depthCollisionsCheckBox.Create("Depth Buffer Collisions Enabled: ");
  	depthCollisionsCheckBox.SetPos(XMFLOAT2(x + 250, y));
  	depthCollisionsCheckBox.SetSize(XMFLOAT2(itemheight, itemheight));
  	depthCollisionsCheckBox.OnClick([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SetDepthCollisionEnabled(args.bValue);
  		}
  	});
  	depthCollisionsCheckBox.SetCheck(false);
  	depthCollisionsCheckBox.SetTooltip("Enable particle collisions with the depth buffer.");
  	AddWidget(&depthCollisionsCheckBox);
  
  
  	sphCheckBox.Create("SPH - FluidSim: ");
  	sphCheckBox.SetPos(XMFLOAT2(x + 400, y));
  	sphCheckBox.SetSize(XMFLOAT2(itemheight, itemheight));
  	sphCheckBox.OnClick([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SetSPHEnabled(args.bValue);
  		}
  	});
  	sphCheckBox.SetCheck(false);
  	sphCheckBox.SetTooltip("Enable particle collisions with each other. Simulate with Smooth Particle Hydrodynamics (SPH) solver.");
  	AddWidget(&sphCheckBox);
  
  
  	pauseCheckBox.Create("PAUSE: ");
  	pauseCheckBox.SetPos(XMFLOAT2(x, y += step));
  	pauseCheckBox.SetSize(XMFLOAT2(itemheight, itemheight));
  	pauseCheckBox.OnClick([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SetPaused(args.bValue);
  		}
  	});
  	pauseCheckBox.SetCheck(false);
  	pauseCheckBox.SetTooltip("Stop simulation update.");
  	AddWidget(&pauseCheckBox);
  
  
  	debugCheckBox.Create("DEBUG: ");
  	debugCheckBox.SetPos(XMFLOAT2(x + 120, y));
  	debugCheckBox.SetSize(XMFLOAT2(itemheight, itemheight));
  	debugCheckBox.OnClick([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SetDebug(args.bValue);
  		}
  	});
  	debugCheckBox.SetCheck(false);
  	debugCheckBox.SetTooltip("Currently this has no functionality.");
  	AddWidget(&debugCheckBox);
  
  
  	volumeCheckBox.Create("Volume: ");
  	volumeCheckBox.SetPos(XMFLOAT2(x + 250, y));
  	volumeCheckBox.SetSize(XMFLOAT2(itemheight, itemheight));
  	volumeCheckBox.OnClick([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SetVolumeEnabled(args.bValue);
  		}
  		});
  	volumeCheckBox.SetCheck(false);
  	volumeCheckBox.SetTooltip("Enable volume for the emitter. Particles will be emitted inside volume.");
  	AddWidget(&volumeCheckBox);
  
  
  	frameBlendingCheckBox.Create("Frame Blending: ");
  	frameBlendingCheckBox.SetPos(XMFLOAT2(x + 400, y));
  	frameBlendingCheckBox.SetSize(XMFLOAT2(itemheight, itemheight));
  	frameBlendingCheckBox.OnClick([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SetFrameBlendingEnabled(args.bValue);
  		}
  		});
  	frameBlendingCheckBox.SetCheck(false);
  	frameBlendingCheckBox.SetTooltip("If sprite sheet animation is in effect, frames will be smoothly blended.");
  	AddWidget(&frameBlendingCheckBox);
  
  
  
  	infoLabel.Create("EmitterInfo");
  	infoLabel.SetSize(XMFLOAT2(380, 120));
  	infoLabel.SetPos(XMFLOAT2(x, y += step));
  	AddWidget(&infoLabel);
  
  
  	y += 125;
  
  	frameRateInput.Create("");
  	frameRateInput.SetPos(XMFLOAT2(x, y));
  	frameRateInput.SetSize(XMFLOAT2(40, 18));
  	frameRateInput.SetText("");
  	frameRateInput.SetTooltip("Enter a value to enable looping sprite sheet animation (frames per second). Set 0 for animation along paritcle lifetime.");
  	frameRateInput.SetDescription("Frame Rate: ");
  	frameRateInput.OnInputAccepted([this](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->frameRate = args.fValue;
  		}
  		});
  	AddWidget(&frameRateInput);
  
  	framesXInput.Create("");
  	framesXInput.SetPos(XMFLOAT2(x + 150, y));
  	framesXInput.SetSize(XMFLOAT2(40, 18));
  	framesXInput.SetText("");
  	framesXInput.SetTooltip("How many horizontal frames there are in the spritesheet.");
  	framesXInput.SetDescription("Frames X: ");
  	framesXInput.OnInputAccepted([this](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->framesX = (uint32_t)args.iValue;
  		}
  		});
  	AddWidget(&framesXInput);
  
  	framesYInput.Create("");
  	framesYInput.SetPos(XMFLOAT2(x + 300, y));
  	framesYInput.SetSize(XMFLOAT2(40, 18));
  	framesYInput.SetText("");
  	framesYInput.SetTooltip("How many vertical frames there are in the spritesheet.");
  	framesYInput.SetDescription("Frames Y: ");
  	framesYInput.OnInputAccepted([this](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->framesY = (uint32_t)args.iValue;
  		}
  		});
  	AddWidget(&framesYInput);
  
  	frameCountInput.Create("");
  	frameCountInput.SetPos(XMFLOAT2(x, y += step));
  	frameCountInput.SetSize(XMFLOAT2(40, 18));
  	frameCountInput.SetText("");
  	frameCountInput.SetTooltip("Enter a value to enable the random sprite sheet frame selection's max frame number.");
  	frameCountInput.SetDescription("Frame Count: ");
  	frameCountInput.OnInputAccepted([this](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->frameCount = (uint32_t)args.iValue;
  		}
  		});
  	AddWidget(&frameCountInput);
  
  	frameStartInput.Create("");
  	frameStartInput.SetPos(XMFLOAT2(x + 300, y));
  	frameStartInput.SetSize(XMFLOAT2(40, 18));
  	frameStartInput.SetText("");
  	frameStartInput.SetTooltip("Specifies the starting frame of the animation.");
  	frameStartInput.SetDescription("Start Frame: ");
  	frameStartInput.OnInputAccepted([this](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->frameStart = (uint32_t)args.iValue;
  		}
  		});
  	AddWidget(&frameStartInput);
  
  
  
  
  	VelocityXInput.Create("");
  	VelocityXInput.SetValue(0);
  	VelocityXInput.SetDescription("Starting Velocity: ");
  	VelocityXInput.SetTooltip("Vector X component");
  	VelocityXInput.SetPos(XMFLOAT2(x, y += step));
  	VelocityXInput.SetSize(XMFLOAT2(38, itemheight));
  	VelocityXInput.OnInputAccepted([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->velocity.x = args.fValue;
  		}
  		});
  	AddWidget(&VelocityXInput);
  
  	VelocityYInput.Create("");
  	VelocityYInput.SetValue(0);
  	VelocityYInput.SetTooltip("Vector Y component");
  	VelocityYInput.SetPos(XMFLOAT2(x + 40, y));
  	VelocityYInput.SetSize(XMFLOAT2(38, itemheight));
  	VelocityYInput.OnInputAccepted([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->velocity.y = args.fValue;
  		}
  		});
  	AddWidget(&VelocityYInput);
  
  	VelocityZInput.Create("");
  	VelocityZInput.SetValue(0);
  	VelocityZInput.SetTooltip("Vector Z component");
  	VelocityZInput.SetPos(XMFLOAT2(x + 80, y));
  	VelocityZInput.SetSize(XMFLOAT2(38, itemheight));
  	VelocityZInput.OnInputAccepted([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->velocity.z = args.fValue;
  		}
  		});
  	AddWidget(&VelocityZInput);
  
  
  
  	GravityXInput.Create("");
  	GravityXInput.SetValue(0);
  	GravityXInput.SetDescription("Gravity: ");
  	GravityXInput.SetTooltip("Vector X component");
  	GravityXInput.SetPos(XMFLOAT2(x + 200, y));
  	GravityXInput.SetSize(XMFLOAT2(38, itemheight));
  	GravityXInput.OnInputAccepted([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->gravity.x = args.fValue;
  		}
  		});
  	AddWidget(&GravityXInput);
  
  	GravityYInput.Create("");
  	GravityYInput.SetValue(0);
  	GravityYInput.SetTooltip("Vector Y component");
  	GravityYInput.SetPos(XMFLOAT2(x + 240, y));
  	GravityYInput.SetSize(XMFLOAT2(38, itemheight));
  	GravityYInput.OnInputAccepted([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->gravity.y = args.fValue;
  		}
  		});
  	AddWidget(&GravityYInput);
  
  	GravityZInput.Create("");
  	GravityZInput.SetValue(0);
  	GravityZInput.SetTooltip("Vector Z component");
  	GravityZInput.SetPos(XMFLOAT2(x + 280, y));
  	GravityZInput.SetSize(XMFLOAT2(38, itemheight));
  	GravityZInput.OnInputAccepted([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->gravity.z = args.fValue;
  		}
  		});
  	AddWidget(&GravityZInput);
  
  	maxParticlesSlider.Create(100.0f, 1000000.0f, 10000, 100000, "Max particle count: ");
  	maxParticlesSlider.SetSize(XMFLOAT2(360, itemheight));
  	maxParticlesSlider.SetPos(XMFLOAT2(x, y += step));
  	maxParticlesSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SetMaxParticleCount((uint32_t)args.iValue);
  		}
  		});
  	maxParticlesSlider.SetEnabled(false);
  	maxParticlesSlider.SetTooltip("Set the maximum amount of particles this system can handle. This has an effect on the memory budget.");
  	AddWidget(&maxParticlesSlider);
  
  	emitCountSlider.Create(0.0f, 10000.0f, 1.0f, 100000, "Emit count per sec: ");
  	emitCountSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitCountSlider.SetPos(XMFLOAT2(x, y += step));
  	emitCountSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->count = args.fValue;
  		}
  	});
  	emitCountSlider.SetEnabled(false);
  	emitCountSlider.SetTooltip("Set the number of particles to emit per second.");
  	AddWidget(&emitCountSlider);
  
  	emitSizeSlider.Create(0.01f, 10.0f, 1.0f, 100000, "Size: ");
  	emitSizeSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitSizeSlider.SetPos(XMFLOAT2(x, y += step));
  	emitSizeSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->size = args.fValue;
  		}
  	});
  	emitSizeSlider.SetEnabled(false);
  	emitSizeSlider.SetTooltip("Set the size of the emitted particles.");
  	AddWidget(&emitSizeSlider);
  
  	emitRotationSlider.Create(0.0f, 1.0f, 0.0f, 100000, "Rotation: ");
  	emitRotationSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitRotationSlider.SetPos(XMFLOAT2(x, y += step));
  	emitRotationSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->rotation = args.fValue;
  		}
  	});
  	emitRotationSlider.SetEnabled(false);
  	emitRotationSlider.SetTooltip("Set the rotation velocity of the emitted particles.");
  	AddWidget(&emitRotationSlider);
  
  	emitNormalSlider.Create(0.0f, 100.0f, 1.0f, 100000, "Normal factor: ");
  	emitNormalSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitNormalSlider.SetPos(XMFLOAT2(x, y += step));
  	emitNormalSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->normal_factor = args.fValue;
  		}
  	});
  	emitNormalSlider.SetEnabled(false);
  	emitNormalSlider.SetTooltip("Set the velocity of the emitted particles based on the normal vector of the emitter surface.");
  	AddWidget(&emitNormalSlider);
  
  	emitScalingSlider.Create(0.0f, 100.0f, 1.0f, 100000, "Scaling: ");
  	emitScalingSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitScalingSlider.SetPos(XMFLOAT2(x, y += step));
  	emitScalingSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->scaleX = args.fValue;
  		}
  	});
  	emitScalingSlider.SetEnabled(false);
  	emitScalingSlider.SetTooltip("Set the scaling of the particles based on their lifetime.");
  	AddWidget(&emitScalingSlider);
  
  	emitLifeSlider.Create(0.0f, 100.0f, 1.0f, 10000, "Life span: ");
  	emitLifeSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitLifeSlider.SetPos(XMFLOAT2(x, y += step));
  	emitLifeSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->life = args.fValue;
  		}
  	});
  	emitLifeSlider.SetEnabled(false);
  	emitLifeSlider.SetTooltip("Set the lifespan of the emitted particles (in seconds).");
  	AddWidget(&emitLifeSlider);
  
  	emitRandomnessSlider.Create(0.0f, 1.0f, 1.0f, 100000, "Randomness: ");
  	emitRandomnessSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitRandomnessSlider.SetPos(XMFLOAT2(x, y += step));
  	emitRandomnessSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->random_factor = args.fValue;
  		}
  	});
  	emitRandomnessSlider.SetEnabled(false);
  	emitRandomnessSlider.SetTooltip("Set the general randomness of the emitter.");
  	AddWidget(&emitRandomnessSlider);
  
  	emitLifeRandomnessSlider.Create(0.0f, 2.0f, 0.0f, 100000, "Life randomness: ");
  	emitLifeRandomnessSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitLifeRandomnessSlider.SetPos(XMFLOAT2(x, y += step));
  	emitLifeRandomnessSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->random_life = args.fValue;
  		}
  	});
  	emitLifeRandomnessSlider.SetEnabled(false);
  	emitLifeRandomnessSlider.SetTooltip("Set the randomness of lifespans for the emitted particles.");
  	AddWidget(&emitLifeRandomnessSlider);
  
  	emitColorRandomnessSlider.Create(0.0f, 2.0f, 0.0f, 100000, "Color randomness: ");
  	emitColorRandomnessSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitColorRandomnessSlider.SetPos(XMFLOAT2(x, y += step));
  	emitColorRandomnessSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->random_color = args.fValue;
  		}
  		});
  	emitColorRandomnessSlider.SetEnabled(false);
  	emitColorRandomnessSlider.SetTooltip("Set the randomness of color for the emitted particles.");
  	AddWidget(&emitColorRandomnessSlider);
  
  	emitMotionBlurSlider.Create(0.0f, 1.0f, 1.0f, 100000, "Motion blur: ");
  	emitMotionBlurSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitMotionBlurSlider.SetPos(XMFLOAT2(x, y += step));
  	emitMotionBlurSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->motionBlurAmount = args.fValue;
  		}
  	});
  	emitMotionBlurSlider.SetEnabled(false);
  	emitMotionBlurSlider.SetTooltip("Set the motion blur amount for the particle system.");
  	AddWidget(&emitMotionBlurSlider);
  
  	emitMassSlider.Create(0.1f, 100.0f, 1.0f, 100000, "Mass: ");
  	emitMassSlider.SetSize(XMFLOAT2(360, itemheight));
  	emitMassSlider.SetPos(XMFLOAT2(x, y += step));
  	emitMassSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->mass = args.fValue;
  		}
  	});
  	emitMassSlider.SetEnabled(false);
  	emitMassSlider.SetTooltip("Set the mass per particle.");
  	AddWidget(&emitMassSlider);
  
  
  
  	timestepSlider.Create(-1, 0.016f, -1, 100000, "Timestep: ");
  	timestepSlider.SetSize(XMFLOAT2(360, itemheight));
  	timestepSlider.SetPos(XMFLOAT2(x, y += step));
  	timestepSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->FIXED_TIMESTEP = args.fValue;
  		}
  	});
  	timestepSlider.SetEnabled(false);
  	timestepSlider.SetTooltip("Adjust timestep for emitter simulation. -1 means variable timestep, positive means fixed timestep.");
  	AddWidget(&timestepSlider);
  
  
  
  	dragSlider.Create(0, 1, 1, 100000, "Drag: ");
  	dragSlider.SetSize(XMFLOAT2(360, itemheight));
  	dragSlider.SetPos(XMFLOAT2(x, y += step));
  	dragSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->drag = args.fValue;
  		}
  		});
  	dragSlider.SetEnabled(false);
  	dragSlider.SetTooltip("The velocity will be multiplied with this value, so lower than 1 will slow decelerate the particles.");
  	AddWidget(&dragSlider);
  
  	restitutionSlider.Create(0, 1, 1, 100000, "Restitution: ");
  	restitutionSlider.SetSize(XMFLOAT2(360, itemheight));
  	restitutionSlider.SetPos(XMFLOAT2(x, y += step));
  	restitutionSlider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->restitution = args.fValue;
  		}
  		});
  	restitutionSlider.SetEnabled(false);
  	restitutionSlider.SetTooltip("If the particles have collision enabled, then after collision this is a multiplier for their bouncing velocities");
  	AddWidget(&restitutionSlider);
  
  
  
  	//////////////// SPH ////////////////////////////
  
  	sph_h_Slider.Create(0.1f, 100.0f, 1.0f, 100000, "SPH Smoothing Radius (h): ");
  	sph_h_Slider.SetSize(XMFLOAT2(360, itemheight));
  	sph_h_Slider.SetPos(XMFLOAT2(x, y += step));
  	sph_h_Slider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SPH_h = args.fValue;
  		}
  	});
  	sph_h_Slider.SetEnabled(false);
  	sph_h_Slider.SetTooltip("Set the SPH parameter: smoothing radius");
  	AddWidget(&sph_h_Slider);
  
  	sph_K_Slider.Create(0.1f, 100.0f, 1.0f, 100000, "SPH Pressure Constant (K): ");
  	sph_K_Slider.SetSize(XMFLOAT2(360, itemheight));
  	sph_K_Slider.SetPos(XMFLOAT2(x, y += step));
  	sph_K_Slider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SPH_K = args.fValue;
  		}
  	});
  	sph_K_Slider.SetEnabled(false);
  	sph_K_Slider.SetTooltip("Set the SPH parameter: pressure constant");
  	AddWidget(&sph_K_Slider);
  
  	sph_p0_Slider.Create(0.1f, 100.0f, 1.0f, 100000, "SPH Reference Density (p0): ");
  	sph_p0_Slider.SetSize(XMFLOAT2(360, itemheight));
  	sph_p0_Slider.SetPos(XMFLOAT2(x, y += step));
  	sph_p0_Slider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SPH_p0 = args.fValue;
  		}
  	});
  	sph_p0_Slider.SetEnabled(false);
  	sph_p0_Slider.SetTooltip("Set the SPH parameter: reference density");
  	AddWidget(&sph_p0_Slider);
  
  	sph_e_Slider.Create(0, 10, 1.0f, 100000, "SPH Viscosity (e): ");
  	sph_e_Slider.SetSize(XMFLOAT2(360, itemheight));
  	sph_e_Slider.SetPos(XMFLOAT2(x, y += step));
  	sph_e_Slider.OnSlide([&](wi::gui::EventArgs args) {
  		auto emitter = GetEmitter();
  		if (emitter != nullptr)
  		{
  			emitter->SPH_e = args.fValue;
  		}
  	});
  	sph_e_Slider.SetEnabled(false);
  	sph_e_Slider.SetTooltip("Set the SPH parameter: viscosity constant");
  	AddWidget(&sph_e_Slider);
  
  
  
  
  
  
  	Translate(XMFLOAT3(200, 50, 0));
  	SetVisible(false);
  
  	SetEntity(entity);
  }
  
  void EmitterWindow::SetEntity(Entity entity)
  {
  	this->entity = entity;
  
  	auto emitter = GetEmitter();
  
  	if (emitter != nullptr)
  	{
  		SetEnabled(true);
  
  		shaderTypeComboBox.SetSelected((int)emitter->shaderType);
  
  		sortCheckBox.SetCheck(emitter->IsSorted());
  		depthCollisionsCheckBox.SetCheck(emitter->IsDepthCollisionEnabled());
  		sphCheckBox.SetCheck(emitter->IsSPHEnabled());
  		pauseCheckBox.SetCheck(emitter->IsPaused());
  		volumeCheckBox.SetCheck(emitter->IsVolumeEnabled());
  		frameBlendingCheckBox.SetCheck(emitter->IsFrameBlendingEnabled());
  		maxParticlesSlider.SetValue((float)emitter->GetMaxParticleCount());
  
  		frameRateInput.SetValue(emitter->frameRate);
  		framesXInput.SetValue((int)emitter->framesX);
  		framesYInput.SetValue((int)emitter->framesY);
  		frameCountInput.SetValue((int)emitter->frameCount);
  		frameStartInput.SetValue((int)emitter->frameStart);
  
  		emitCountSlider.SetValue(emitter->count);
  		emitSizeSlider.SetValue(emitter->size);
  		emitRotationSlider.SetValue(emitter->rotation);
  		emitNormalSlider.SetValue(emitter->normal_factor);
  		emitScalingSlider.SetValue(emitter->scaleX);
  		emitLifeSlider.SetValue(emitter->life);
  		emitRandomnessSlider.SetValue(emitter->random_factor);
  		emitLifeRandomnessSlider.SetValue(emitter->random_life);
  		emitColorRandomnessSlider.SetValue(emitter->random_color);
  		emitMotionBlurSlider.SetValue(emitter->motionBlurAmount);
  		emitMassSlider.SetValue(emitter->mass);
  		timestepSlider.SetValue(emitter->FIXED_TIMESTEP);
  		dragSlider.SetValue(emitter->drag);
  		restitutionSlider.SetValue(emitter->restitution);
  		VelocityXInput.SetValue(emitter->velocity.x);
  		VelocityYInput.SetValue(emitter->velocity.y);
  		VelocityZInput.SetValue(emitter->velocity.z);
  		GravityXInput.SetValue(emitter->gravity.x);
  		GravityYInput.SetValue(emitter->gravity.y);
  		GravityZInput.SetValue(emitter->gravity.z);
  
  		sph_h_Slider.SetValue(emitter->SPH_h);
  		sph_K_Slider.SetValue(emitter->SPH_K);
  		sph_p0_Slider.SetValue(emitter->SPH_p0);
  		sph_e_Slider.SetValue(emitter->SPH_e);
  
  		debugCheckBox.SetCheck(emitter->IsDebug());
  	}
  	else
  	{
  		infoLabel.SetText("No emitter object selected.");
  
  		SetEnabled(false);
  
  		addButton.SetEnabled(true);
  	}
  
  }
  
  wi::EmittedParticleSystem* EmitterWindow::GetEmitter()
  {
  	if (entity == INVALID_ENTITY)
  	{
  		return nullptr;
  	}
  
  	Scene& scene = wi::scene::GetScene();
  	wi::EmittedParticleSystem* emitter = scene.emitters.GetComponent(entity);
  
  	return emitter;
  }
  
  void EmitterWindow::UpdateData()
  {
  	auto emitter = GetEmitter();
  	if (emitter == nullptr)
  	{
  		return;
  	}
  
  	Scene& scene = wi::scene::GetScene();
  
  	meshComboBox.ClearItems();
  	meshComboBox.AddItem("NO MESH");
  	for (size_t i = 0; i < scene.meshes.GetCount(); ++i)
  	{
  		Entity entity = scene.meshes.GetEntity(i);
  		const NameComponent& name = *scene.names.GetComponent(entity);
  		meshComboBox.AddItem(name.name);
  
  		if (emitter->meshID == entity)
  		{
  			meshComboBox.SetSelected((int)i + 1);
  		}
  	}
  
  	NameComponent* name = scene.names.GetComponent(entity);
  	NameComponent* meshName = scene.names.GetComponent(emitter->meshID);
  
  	std::string ss;
  	ss += "Emitter Mesh: " + (meshName != nullptr ? meshName->name : "NO EMITTER MESH") + " (" + std::to_string(emitter->meshID) + ")\n";
  	ss += "Memort Budget: " + std::to_string(emitter->GetMemorySizeInBytes() / 1024.0f / 1024.0f) + " MB\n";
  	ss += "\n";
  
  	auto data = emitter->GetStatistics();
  	ss += "Alive Particle Count = " + std::to_string(data.aliveCount) + "\n";
  	ss += "Dead Particle Count = " + std::to_string(data.deadCount) + "\n";
  	ss += "GPU Emit count = " + std::to_string(data.realEmitCount) + "\n";
  	ss += "Visible after frustum culling = " + std::to_string(data.culledCount) + "\n";
  
  	infoLabel.SetText(ss);
  
  	emitterNameField.SetText(name->name);
  }
  