DirectX11의 Particle Editor는 DirectX11 응용 프로그램에서 사용할 입자 효과를 만들고 관리하는 데 사용되는 소프트웨어 도구이다. 그것은 개발자들이 개별 입자의 행동과 모양을 제어함으로써 연기, 화재, 물, 폭발과 같은 복잡하고 역동적인 효과를 만들 수 있게 한다.

 

목차

     

     


     

     

     

     

    Particle Editor

     

    파티클 편집기에는 일반적으로 개발자가 파티클 시스템을 시각적으로 만들고 수정할 수 있는 시각적 편집기가 포함되어 있다. 일반적으로 크기, 색상, 불투명도 및 수명과 같은 입자 속성에 대한 제어를 제공하며 개발자가 입자 시스템의 동작 및 모양을 실시간으로 조정할 수 있다. 또한 DirectX11의 Particle Editor는 개발자가 입자에 이미지를 적용할 수 있는 텍스처 매핑 및 고급 물리 시뮬레이션과 같은 기능을 제공하여 보다 현실적인 입자 효과를 생성할 수 있다.

    파티클 시스템이 생성되면 XML 또는 JSON과 같은 다양한 파일 형식으로 내보낼 수 있으며, DirectX11 응용 프로그램에서 쉽게 로드하고 사용할 수 있다. 내보낸 입자 시스템은 개발자가 고급 입자 효과를 효율적으로 구현할 수 있는 Direct3D 11 Compute Shader와 같은 DirectX11의 입자 시스템 API를 사용하여 애플리케이션에 통합할 수 있다.

     

     

    Shaders
      Particle.fx
    Framework
      Particle
      ParticleData.h
    ParticleSystem.h .cpp
    ParticleEditor
      Editor.h .cpp 생성
    Viewer.h. cpp
    Main.h .cpp
       

     

     


     

    ParticleSystem

     

    ParticleSystem.h

    더보기
    #pragma once
    
    class ParticleSystem : public Renderer
    {
    public:
    	ParticleSystem(wstring file);
    	~ParticleSystem();
    
    	void Reset(); //초기화 함수
    	void Add(Vector3& position); //외부에서 추가
    
    public:
    	void Update();//업데이트 함수. 외부에서 Update를 콜할때 사용
    
    private:
    	void MapVertices();
    	void Activate();
    	void Deactivate();
    
    public:
    	void Render();
    
    	ParticleData& GetData() { return data; }
    	void SetTexture(wstring file);
    
    
    private:
    	void ReadFile(wstring file);
    
    private:
    	struct VertexParticle
    	{
    		Vector3 Position;
    		Vector2 Corner; //(-1 ~ +1)
    		Vector3 Velocity; //파티클이 움직이는 속도
    		Vector4 Random; //x:주기, y:크기, z:회전, w:색상
    		float Time; //현재 속도
    	};
    
    private:
    	struct Desc
    	{
    		Color MinColor;
    		Color MaxColor;
    
    		Vector3 Gravity;
    		float EndVelocity;
    
    		Vector2 StartSize;
    		Vector2 EndSize;
    
    		Vector2 RotateSpeed;
    		float ReadyTime;
    		float ReadyRandomTime;
    
    		float ColorAmount;
    		float CurrentTime;
    		float Padding[2];
    	} desc;
    
    private:
    	ParticleData data; //파티클 정보
    
    	Texture* map = NULL; 
    	ID3DX11EffectShaderResourceVariable* sMap;
    
    	ConstantBuffer* buffer;
    	ID3DX11EffectConstantBuffer* sBuffer;
    
    
    	VertexParticle* vertices = NULL;
    	UINT* indices = NULL;
    
    	float currentTime = 0.0f; //현재 시간
    	float lastAddTime = 0.0f; //마지막 파티클이 추가된 시간
    
    	UINT leadCount = 0;
    	UINT gpuCount = 0;
    	UINT activeCount = 0;
    	UINT deactiveCount = 0;
    };

     

     

     

    ParticleSystem.cpp

    더보기
    #include "Framework.h"
    #include "ParticleSystem.h"
    #include "Utilities/Xml.h"
    
    ParticleSystem::ParticleSystem(wstring file)
    	: Renderer(L"89_Particle.fxo")
    {
    	ReadFile(L"../../_Textures/Particles/" + file + L".xml");//.xml파일을 읽는다.
    
    	buffer = new ConstantBuffer(&desc, sizeof(Desc));
    	sBuffer = shader->AsConstantBuffer("CB_Particle");
    
    	sMap = shader->AsSRV("ParticleMap");
    
    	Reset();
    }
    
    ParticleSystem::~ParticleSystem()
    {
    	SafeDelete(map);
    	SafeDelete(buffer);
    
    	SafeDeleteArray(vertices);
    	SafeDeleteArray(indices);
    }
    
    void ParticleSystem::Reset()
    {
    	currentTime = 0.0f;
    	lastAddTime = Time::Get()->Running();
    	gpuCount = leadCount = activeCount = deactiveCount = 0;
    
    
    	SafeDeleteArray(vertices);
    	SafeDeleteArray(indices);
    
    	SafeDelete(vertexBuffer);
    	SafeDelete(indexBuffer);
    
    	vertices = new VertexParticle[data.MaxParticles * 4];
    	for (UINT i = 0; i < data.MaxParticles; i++)
    	{
    		vertices[i * 4 + 0].Corner = Vector2(-1, -1);
    		vertices[i * 4 + 1].Corner = Vector2(-1, +1);
    		vertices[i * 4 + 2].Corner = Vector2(+1, -1);
    		vertices[i * 4 + 3].Corner = Vector2(+1, +1);
    	}
    
    	indices = new UINT[data.MaxParticles * 6];
    	for (UINT i = 0; i < data.MaxParticles; i++)
    	{
    		indices[i * 6 + 0] = i * 4 + 0;
    		indices[i * 6 + 1] = i * 4 + 1;
    		indices[i * 6 + 2] = i * 4 + 2;
    		indices[i * 6 + 3] = i * 4 + 2;
    		indices[i * 6 + 4] = i * 4 + 1;
    		indices[i * 6 + 5] = i * 4 + 3;
    	}
    
    	vertexBuffer = new VertexBuffer(vertices, data.MaxParticles * 4, sizeof(VertexParticle), 0, true); //정점 버퍼
    	indexBuffer = new IndexBuffer(indices, data.MaxParticles * 6); //인덱스 버퍼
    }
    
    void ParticleSystem::Add(Vector3 & position)
    {
    	if (Time::Get()->Running() - lastAddTime < 60.0f / 1000.0f) //60프레임 제한
    		return;
    
    	lastAddTime = Time::Get()->Running();
    
    
    	UINT count = leadCount + 1; //시작해서 갈 카운트
    
    	if (count >= data.MaxParticles)
    	{
    		if (data.bLoop == true)
    		{
    			count = 0;
    		}
    		else
    		{
    			count = data.MaxParticles;
    
    			return;
    		}
    	}
    		
    
    	if (count == deactiveCount)
    		return;
    
    
    	Vector3 velocity = Vector3(1, 1, 1); //기본 속도이자 방향
    	velocity *= data.StartVelocity;
    
    	float horizontalVelocity = Math::Lerp(data.MinHorizontalVelocity, data.MaxHorizontalVelocity, Math::Random(0.0f, 1.0f));//수평이동 속도를 선형보간으로 만든다.
    	float horizontalAngle = Math::PI * 2.0f * Math::Random(0.0f, 1.0f);//z방향 회전
    
    	velocity.x += horizontalVelocity * cosf(horizontalAngle);//x속도
    	velocity.y += horizontalVelocity * sinf(horizontalAngle);//y속도
    	velocity.z += Math::Lerp(data.MinHorizontalVelocity, data.MaxHorizontalVelocity, Math::Random(0.0f, 1.0f));//z속도
    
    
    	Vector4 random = Math::RandomVec4(0.0f, 1.0f);
    
    	for (UINT i = 0; i < 4; i++)
    	{
    		vertices[leadCount * 4 + i].Position = position;
    		vertices[leadCount * 4 + i].Velocity = velocity;
    		vertices[leadCount * 4 + i].Random = random;
    		vertices[leadCount * 4 + i].Time = currentTime;
    	}
    
    	leadCount = count;
    }
    
    void ParticleSystem::Update()
    {
    	Super::Update();
    
    	currentTime += Time::Delta();
    
    	MapVertices();
    	Activate();
    	Deactivate();
    
    	if (activeCount == leadCount)
    		currentTime = 0.0f;
    
    
    	desc.MinColor = data.MinColor;
    	desc.MaxColor = data.MaxColor;
    	desc.ColorAmount = data.ColorAmount;
    
    	desc.Gravity = data.Gravity;
    	desc.EndVelocity = data.EndVelocity;
    
    	desc.RotateSpeed = Vector2(data.MinRotateSpeed, data.MaxRotateSpeed);
    	desc.StartSize = Vector2(data.MinStartSize, data.MaxStartSize);
    	desc.EndSize = Vector2(data.MinEndSize, data.MaxEndSize);
    
    	desc.ReadyTime = data.ReadyTime;
    	desc.ReadyRandomTime = data.ReadyRandomTime;
    }
    
    void ParticleSystem::MapVertices()
    {
    	if (gpuCount == leadCount) return;
    
    	D3D11_MAPPED_SUBRESOURCE subResource;
    
    	if (leadCount > gpuCount)
    	{
    		D3D::GetDC()->Map(vertexBuffer->Buffer(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &subResource);
    		{
    			UINT start = gpuCount * 4;
    			UINT size = (leadCount - gpuCount) * sizeof(VertexParticle) * 4;
    			UINT offset = gpuCount * sizeof(VertexParticle) * 4;
    
    			BYTE* p = (BYTE *)subResource.pData + offset;
    			memcpy(p, vertices + start, size);
    		}
    		D3D::GetDC()->Unmap(vertexBuffer->Buffer(), 0);
    	}
    	else //(leadCount < gpuCount)인 경우
    	{
    		D3D::GetDC()->Map(vertexBuffer->Buffer(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &subResource);
    		{
    			UINT start = gpuCount * 4;
    			UINT size = (data.MaxParticles - gpuCount) * sizeof(VertexParticle) * 4;
    			UINT offset = gpuCount * sizeof(VertexParticle) * 4;
    
    			BYTE* p = (BYTE *)subResource.pData + offset;
    			memcpy(p, vertices + start, size);
    		}
    
    		if (leadCount > 0)
    		{
    			UINT size = leadCount * sizeof(VertexParticle) * 4;
    
    			memcpy(subResource.pData, vertices, size);
    		}
    
    		D3D::GetDC()->Unmap(vertexBuffer->Buffer(), 0);
    	}
    
    	gpuCount = leadCount;
    }
    
    void ParticleSystem::Activate()
    {
    	while (activeCount != gpuCount)
    	{
    		float age = currentTime - vertices[activeCount * 4].Time;
    
    		if (age < data.ReadyTime)
    			return;
    
    		vertices[activeCount * 4].Time = currentTime;
    		activeCount++;
    
    		if (activeCount >= data.MaxParticles)
    			activeCount = (data.bLoop == true) ? 0 : data.MaxParticles;
    	}
    }
    
    void ParticleSystem::Deactivate()
    {
    	while (activeCount != deactiveCount)
    	{
    		float age = currentTime - vertices[deactiveCount * 4].Time;
    
    		if (age > data.ReadyTime)
    			return;
    
    		deactiveCount++;
    
    		if (deactiveCount >= data.MaxParticles)
    			deactiveCount = (data.bLoop == true) ? 0 : data.MaxParticles;
    	}
    }
    
    void ParticleSystem::Render()
    {
    	Super::Render();
    
    
    	desc.CurrentTime = currentTime;
    
    	buffer->Render();
    	sBuffer->SetConstantBuffer(buffer->Buffer());
    
    	sMap->SetResource(map->SRV());
    
    	if (leadCount == activeCount) 
    		return;
    
    
    	UINT pass = (UINT)data.Type;
    	if (leadCount > activeCount)
    	{
    		shader->DrawIndexed(0, pass, (leadCount - activeCount) * 6, activeCount * 6);
    	}
    	else
    	{
    		shader->DrawIndexed(0, pass, (data.MaxParticles - activeCount) * 6, activeCount * 6);
    
    		if (leadCount > 0)
    			shader->DrawIndexed(0, pass, leadCount * 6);
    	}
    }
    
    void ParticleSystem::SetTexture(wstring file)
    {
    	SafeDelete(map);
    
    	map = new Texture(file);
    }
    
    void ParticleSystem::ReadFile(wstring file)
    {
    	Xml::XMLDocument* document = new Xml::XMLDocument();
    	Xml::XMLError error = document->LoadFile(String::ToString(file).c_str());
    	assert(error == Xml::XML_SUCCESS);
    
    	Xml::XMLElement* root = document->FirstChildElement();
    
    	Xml::XMLElement* node = root->FirstChildElement();
    	data.Type = (ParticleData::BlendType)node->IntText();
    
    	node = node->NextSiblingElement();
    	data.bLoop = node->BoolText();
    
    	node = node->NextSiblingElement();
    	wstring textureFile = String::ToWString(node->GetText());
    	data.TextureFile = L"Particles/" + textureFile;
    	map = new Texture(data.TextureFile);
    
    
    	node = node->NextSiblingElement();
    	data.MaxParticles = node->IntText();
    
    	node = node->NextSiblingElement();
    	data.ReadyTime = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.ReadyRandomTime = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.StartVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.EndVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinHorizontalVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxHorizontalVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinVerticalVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxVerticalVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.Gravity.x = node->FloatAttribute("X");
    	data.Gravity.y = node->FloatAttribute("Y");
    	data.Gravity.z = node->FloatAttribute("Z");
    
    	node = node->NextSiblingElement();
    	data.ColorAmount = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinColor.r = node->FloatAttribute("R");
    	data.MinColor.g = node->FloatAttribute("G");
    	data.MinColor.b = node->FloatAttribute("B");
    	data.MinColor.a = node->FloatAttribute("A");
    
    	node = node->NextSiblingElement();
    	data.MaxColor.r = node->FloatAttribute("R");
    	data.MaxColor.g = node->FloatAttribute("G");
    	data.MaxColor.b = node->FloatAttribute("B");
    	data.MaxColor.a = node->FloatAttribute("A");
    
    	node = node->NextSiblingElement();
    	data.MinRotateSpeed = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxRotateSpeed = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinStartSize = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxStartSize = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinEndSize = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxEndSize = node->FloatText();
    
    	SafeDelete(document);
    }

     

     


     

     

    Editor

     

    Editor.h

    더보기
    #pragma once
    #include "Systems/IExecute.h"
    
    class Editor : public IExecute
    {
    public:
    	virtual void Initialize() override;
    	virtual void Ready() override {}
    	virtual void Destroy() override;
    	virtual void Update() override;
    	virtual void PreRender() override {}
    	virtual void Render() override;
    	virtual void PostRender() override {}
    	virtual void ResizeScreen() override {}
    
    private:
    	void Mesh();
    
    private:
    	void UpdateParticleList();
    	void UpdateTextureList();
    
    	void OnGUI();
    	void OnGUI_List();
    	void OnGUI_Settings();
    	void OnGUI_Write();
    
    	void WriteFile(wstring file);
    
    private:
    	Shader* shader;
    	CubeSky* sky;
    
    	
    	float windowWidth = 500; //윈도우 창 너비
    
    	bool bLoop = false; //루프 
    	UINT maxParticle = 0;
    
    	vector<wstring> particleList; 
    	vector<wstring> textureList; //particle 폴더 안의 textureList
    
    	wstring file = L""; //선택한 파일명을 저장하는 변수
    
    	ParticleSystem* particleSystem = NULL;
    
    
    	Material* floor;
    	Material* stone;
    
    	MeshRender* sphere;
    	MeshRender* grid;
    };

     

     

    Editor.cpp

    더보기
    #include "stdafx.h"
    #include "Editor.h"
    #include "Utilities/Xml.h"
    
    void Editor::Initialize()
    {
    	Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
    	Context::Get()->GetCamera()->Position(1, 36, -85);
    	((Freedom *)Context::Get()->GetCamera())->Speed(50, 2);
    
    
    	shader = new Shader(L"82_NormalMapping.fxo");
    	sky = new CubeSky(L"Environment/GrassCube1024.dds");
    
    	Mesh();
    
    
    	UpdateParticleList(); //ParticleList 갱신
    	UpdateTextureList(); //TextureList 갱신
    }
    
    void Editor::Destroy()
    {
    	
    }
    
    void Editor::Update()
    {
    	OnGUI();
    
    
    	sky->Update();
    
    	sphere->Update();
    	grid->Update();
    
    	
    	Vector3 position;
    	sphere->GetTransform(0)->Position(&position);
    
    	if (Keyboard::Get()->Press('L'))
    		position.x += 20 * Time::Delta();
    	else if (Keyboard::Get()->Press('J'))
    		position.x -= 20 * Time::Delta();
    
    	if (Keyboard::Get()->Press('I'))
    		position.z += 20 * Time::Delta();
    	else if (Keyboard::Get()->Press('K'))
    		position.z -= 20 * Time::Delta();
    
    	if (Keyboard::Get()->Press('O'))
    		position.y += 20 * Time::Delta();
    	else if (Keyboard::Get()->Press('U'))
    		position.y -= 20 * Time::Delta();
    
    	sphere->GetTransform(0)->Position(position);
    	sphere->UpdateTransforms();
    
    	if (particleSystem != NULL)
    	{
    		particleSystem->Add(position);
    		particleSystem->Update();
    	}
    }
    
    void Editor::Render()
    {
    	sky->Render();
    
    	stone->Render();
    	sphere->Render();
    
    	floor->Render();
    	grid->Render();
    
    	if (particleSystem != NULL)
    		particleSystem->Render();
    }
    
    void Editor::Mesh()
    {
    	floor = new Material(shader);
    	floor->DiffuseMap("Floor.png");
    	floor->Specular(1, 1, 1, 20);
    	floor->SpecularMap("Floor_Specular.png");
    	floor->NormalMap("Floor_Normal.png");
    
    	stone = new Material(shader);
    	stone->DiffuseMap("Stones.png");
    	stone->Specular(1, 1, 1, 20);
    	stone->SpecularMap("Stones_Specular.png");
    	stone->Emissive(0.15f, 0.15f, 0.15f, 0.3f);
    	stone->NormalMap("Stones_Normal.png");
    
    
    	Transform* transform = NULL;
    
    	grid = new MeshRender(shader, new MeshGrid(5, 5));
    	transform = grid->AddTransform();
    	transform->Position(0, 0, 0);
    	transform->Scale(12, 1, 12);
    	grid->UpdateTransforms();
    
    	sphere = new MeshRender(shader, new MeshSphere(0.5f, 20, 20));
    	transform = sphere->AddTransform();
    	transform->Position(0, 5, 0);
    	transform->Scale(5, 5, 5);
    	sphere->UpdateTransforms();
    }
    
    void Editor::UpdateParticleList()
    {
    	particleList.clear();
    	Path::GetFiles(&particleList, L"../../_Textures/Particles/", L"*.xml", false); //Particles폴더 내의 .xml 파일들을 가져온다. 이때 자식폴더는 검색하지 않는다.
    
    	for (wstring& file : particleList)
    		file = Path::GetFileNameWithoutExtension(file); //파일을 확장자 제거하여 가져온다.
    }
    
    void Editor::UpdateTextureList()
    {
    	textureList.clear();
    
    	vector<wstring> files;
    	Path::GetFiles(&files, L"../../_Textures/Particles/", L"*.*", false);
    
    	for (wstring file : files)
    	{
    		wstring ext = Path::GetExtension(file);
    		transform(ext.begin(), ext.end(), ext.begin(), toupper);
    
    		file = Path::GetFileName(file);
    		if (ext == L"PNG" || ext == L"TGA" || ext == L"JPG")
    			textureList.push_back(file); //png, tga, jpg이면 가져와서 넣어준다.
    	}
    }
    
    void Editor::OnGUI()
    {
    	float width = D3D::Width();
    	float height = D3D::Height();
    
    	bool bOpen = true;
    	bOpen = ImGui::Begin("Particle", &bOpen);
    	ImGui::SetWindowPos(ImVec2(width - windowWidth, 0));
    	ImGui::SetWindowSize(ImVec2(windowWidth, height));
    	{
    		OnGUI_List();
    		OnGUI_Settings();
    	}
    	ImGui::End();
    }
    
    void Editor::OnGUI_List()
    {
    	if (ImGui::CollapsingHeader("Particle List", ImGuiTreeNodeFlags_DefaultOpen))//CollapsingHeader는 눌러서 펼치게 해주는 역할
    	{
    		for (UINT i = 0; i < particleList.size(); i++)
    		{
    			if (ImGui::Button(String::ToString(particleList[i]).c_str(), ImVec2(200, 0)))
    			{
    				SafeDelete(particleSystem);//파티클 지움
    
    				file = particleList[i];//선택한 파일 저장
    				particleSystem = new ParticleSystem(particleList[i]);
    
    				bLoop = particleSystem->GetData().bLoop;
    				maxParticle = particleSystem->GetData().MaxParticles;
    			}
    		}//for(i)
    	}//ImGui::CollapsingHeader
    }
    
    void Editor::OnGUI_Settings()
    {
    	if (particleSystem == NULL) return;
    
    	ImGui::Spacing();
    
    	if (ImGui::CollapsingHeader("Particle Settings", ImGuiTreeNodeFlags_DefaultOpen))
    	{
    		ImGui::Separator();
    
    		ImGui::SliderInt("MaxParticles", (int *)&maxParticle, 1, 1000);
    		ImGui::Checkbox("Loop", &bLoop);
    
    		if (ImGui::Button("Apply"))
    		{
    			particleSystem->GetData().bLoop = bLoop;
    			particleSystem->GetData().MaxParticles = maxParticle;
    			particleSystem->Reset();
    		}
    
    
    		ImGui::Separator();
    
    		const char* types[] = { "Opaque", "Additive", "AlphaBlend" };
    		ImGui::Combo("BlendType", (int *)&particleSystem->GetData().Type, types, 3);
    
    		ImGui::SliderFloat("ReadyTime", &particleSystem->GetData().ReadyTime, 0.1f, 10.0f);
    		ImGui::SliderFloat("ReadyRandomTime", &particleSystem->GetData().ReadyRandomTime, 0.0f, 100.0f);
    
    		ImGui::SliderFloat("StartVelocity", &particleSystem->GetData().StartVelocity, 0.0f, 10.0f);
    		ImGui::SliderFloat("EndVelocity", &particleSystem->GetData().EndVelocity, -100.0f, 100.0f);
    
    		ImGui::SliderFloat("MinHorizontalVelocity", &particleSystem->GetData().MinHorizontalVelocity, -100.0f, 100.0f);
    		ImGui::SliderFloat("MaxHorizontalVelocity", &particleSystem->GetData().MaxHorizontalVelocity, -100.0f, 100.0f);
    
    		ImGui::SliderFloat("MinVerticalVelocity", &particleSystem->GetData().MinVerticalVelocity, -100.0f, 100.0f);
    		ImGui::SliderFloat("MaxVerticalVelocity", &particleSystem->GetData().MaxVerticalVelocity, -100.0f, 100.0f);
    
    		ImGui::SliderFloat3("Gravity", particleSystem->GetData().Gravity, -100, 100);
    
    		ImGui::SliderFloat("Color Amount", &particleSystem->GetData().ColorAmount, 0.1f, 5.0f);
    
    		ImGui::ColorEdit4("MinColor", particleSystem->GetData().MinColor);
    		ImGui::ColorEdit4("MaxColor", particleSystem->GetData().MaxColor);
    
    		ImGui::SliderFloat("MinRotateSpeed", &particleSystem->GetData().MinRotateSpeed, -10, 10);
    		ImGui::SliderFloat("MaxRotateSpeed", &particleSystem->GetData().MaxRotateSpeed, -10, 10);
    
    		ImGui::SliderFloat("MinStartSize", &particleSystem->GetData().MinStartSize, 0, 500);
    		ImGui::SliderFloat("MaxStartSize", &particleSystem->GetData().MaxStartSize, 0, 500);
    
    		ImGui::SliderFloat("MinEndSize", &particleSystem->GetData().MinEndSize, 0, 500);
    		ImGui::SliderFloat("MaxEndSize", &particleSystem->GetData().MaxEndSize, 0, 500);
    
    		ImGui::Spacing();
    		OnGUI_Write();
    
    
    		ImGui::Spacing();
    		ImGui::Separator();
    		if (ImGui::CollapsingHeader("TextureList", ImGuiTreeNodeFlags_DefaultOpen))
    		{
    			for (wstring textureFile : textureList)
    			{
    				if (ImGui::Button(String::ToString(textureFile).c_str(), ImVec2(200, 0)))
    				{
    					particleSystem->GetData().TextureFile = textureFile;
    					particleSystem->SetTexture(L"Particles/" + textureFile);
    				}
    			}//for(i)
    		}
    	}
    }
    
    void Editor::OnGUI_Write()
    {
    	ImGui::Separator();
    
    	if (ImGui::Button("WriteParticle"))
    	{
    		D3DDesc desc = D3D::GetDesc();
    
    		Path::SaveFileDialog
    		(
    			file, L"Particle file\0*.xml", L"../../_Textures/Particles",
    			bind(&Editor::WriteFile, this, placeholders::_1),
    			desc.Handle
    		);
    	}
    }
    
    void Editor::WriteFile(wstring file)
    {
    	Xml::XMLDocument* document = new Xml::XMLDocument();
    
    	Xml::XMLDeclaration* decl = document->NewDeclaration();
    	document->LinkEndChild(decl);
    
    	Xml::XMLElement* root = document->NewElement("Particle");
    	root->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    	root->SetAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
    	document->LinkEndChild(root);
    
    
    	Xml::XMLElement* node = NULL;
    
    	node = document->NewElement("BlendState");
    	node->SetText((int)particleSystem->GetData().Type);
    	root->LinkEndChild(node);
    
    
    	string textureFile = String::ToString(particleSystem->GetData().TextureFile);
    	String::Replace(&textureFile, "Particles/", "");
    
    	node = document->NewElement("Loop");
    	node->SetText(particleSystem->GetData().bLoop);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("TextureFile");
    	node->SetText(textureFile.c_str());
    	root->LinkEndChild(node);
    
    
    	node = document->NewElement("MaxParticles");
    	node->SetText(particleSystem->GetData().MaxParticles);
    	root->LinkEndChild(node);
    
    
    	node = document->NewElement("ReadyTime");
    	node->SetText(particleSystem->GetData().ReadyTime);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("ReadyRandomTime");
    	node->SetText(particleSystem->GetData().ReadyRandomTime);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("StartVelocity");
    	node->SetText(particleSystem->GetData().StartVelocity);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("EndVelocity");
    	node->SetText(particleSystem->GetData().EndVelocity);
    	root->LinkEndChild(node);
    
    
    	node = document->NewElement("MinHorizontalVelocity");
    	node->SetText(particleSystem->GetData().MinHorizontalVelocity);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MaxHorizontalVelocity");
    	node->SetText(particleSystem->GetData().MaxHorizontalVelocity);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MinVerticalVelocity");
    	node->SetText(particleSystem->GetData().MinVerticalVelocity);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MaxVerticalVelocity");
    	node->SetText(particleSystem->GetData().MaxVerticalVelocity);
    	root->LinkEndChild(node);
    
    
    	node = document->NewElement("Gravity");
    	node->SetAttribute("X", particleSystem->GetData().Gravity.x);
    	node->SetAttribute("Y", particleSystem->GetData().Gravity.y);
    	node->SetAttribute("Z", particleSystem->GetData().Gravity.z);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("ColorAmount");
    	node->SetText(particleSystem->GetData().ColorAmount);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MinColor");
    	node->SetAttribute("R", particleSystem->GetData().MinColor.r);
    	node->SetAttribute("G", particleSystem->GetData().MinColor.g);
    	node->SetAttribute("B", particleSystem->GetData().MinColor.b);
    	node->SetAttribute("A", particleSystem->GetData().MinColor.a);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MaxColor");
    	node->SetAttribute("R", particleSystem->GetData().MaxColor.r);
    	node->SetAttribute("G", particleSystem->GetData().MaxColor.g);
    	node->SetAttribute("B", particleSystem->GetData().MaxColor.b);
    	node->SetAttribute("A", particleSystem->GetData().MaxColor.a);
    	root->LinkEndChild(node);
    
    
    	node = document->NewElement("MinRotateSpeed");
    	node->SetText(particleSystem->GetData().MinRotateSpeed);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MaxRotateSpeed");
    	node->SetText(particleSystem->GetData().MaxRotateSpeed);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MinStartSize");
    	node->SetText((int)particleSystem->GetData().MinStartSize);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MaxStartSize");
    	node->SetText((int)particleSystem->GetData().MaxStartSize);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MinEndSize");
    	node->SetText((int)particleSystem->GetData().MinEndSize);
    	root->LinkEndChild(node);
    
    	node = document->NewElement("MaxEndSize");
    	node->SetText((int)particleSystem->GetData().MaxEndSize);
    	root->LinkEndChild(node);
    
    	wstring folder = Path::GetDirectoryName(file);
    	wstring fileName = Path::GetFileNameWithoutExtension(file);
    
    	document->SaveFile(String::ToString(folder + fileName + L".xml").c_str());
    	SafeDelete(document);
    
    	UpdateParticleList();
    }

     


     

     

    실행화면