commit e79b8f3ed201cd9ac6718f642459ff80d857e4b8
Author: Nanako <469449812@qq.com>
Date: Thu Jan 25 11:21:15 2024 +0800
Init
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..abc5782
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/Binaries
+/.vs
+/.idea
+/Intermediate
+/Saved
diff --git a/.vsconfig b/.vsconfig
new file mode 100644
index 0000000..1a9d718
--- /dev/null
+++ b/.vsconfig
@@ -0,0 +1,13 @@
+{
+ "version": "1.0",
+ "components": [
+ "Microsoft.Net.Component.4.6.2.TargetingPack",
+ "Microsoft.VisualStudio.Component.VC.14.36.17.6.x86.x64",
+ "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
+ "Microsoft.VisualStudio.Component.Windows10SDK.22000",
+ "Microsoft.VisualStudio.Workload.CoreEditor",
+ "Microsoft.VisualStudio.Workload.ManagedDesktop",
+ "Microsoft.VisualStudio.Workload.NativeDesktop",
+ "Microsoft.VisualStudio.Workload.NativeGame"
+ ]
+}
diff --git a/Arona.sln b/Arona.sln
new file mode 100644
index 0000000..8397450
--- /dev/null
+++ b/Arona.sln
@@ -0,0 +1,1846 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31314.256
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Automation", "Automation", "{0BFBE63A-B98A-3411-8EEB-8918FEC737B3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{233774A8-CC9D-3FA9-86D1-90573E92B704}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Programs", "Programs", "{A338B9E2-A559-34BE-A46D-F789DD488FAD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Rules", "Rules", "{C2F57ECE-B26F-39D8-BDA7-C1D40BD8F180}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{57713676-9DBE-331C-AD10-26632AC9EE0C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Arona", "Intermediate\ProjectFiles\Arona.vcxproj", "{BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F5380A68-9385-3B6D-A865-F65F23932F60} = {F5380A68-9385-3B6D-A865-F65F23932F60}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE5", "Intermediate\ProjectFiles\UE5.vcxproj", "{FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F5380A68-9385-3B6D-A865-F65F23932F60} = {F5380A68-9385-3B6D-A865-F65F23932F60}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnrealBuildTool", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\UnrealBuildTool\UnrealBuildTool.csproj", "{F5380A68-9385-3B6D-A865-F65F23932F60}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutomationTool", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\AutomationTool.csproj", "{E828FDF7-9B98-3750-9291-83F3881BB322}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Android\Android.Automation.csproj", "{87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apple.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Apple\Apple.Automation.csproj", "{351A56DD-47EF-3C72-88C7-E8D454E0D53D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutomationUtils.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\AutomationUtils\AutomationUtils.Automation.csproj", "{60768F89-46FE-3C70-9D7C-9DFF15015AD5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildGraph.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\BuildGraph\BuildGraph.Automation.csproj", "{C8F75792-3814-3365-92CD-90A3E8A37A94}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CookedEditor.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\CookedEditor\CookedEditor.Automation.csproj", "{8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrowdinLocalization.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\CrowdinLocalization\CrowdinLocalization.Automation.csproj", "{A338EC7C-9C0B-3113-904A-777A3EDEC8B6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gauntlet.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Gauntlet\Gauntlet.Automation.csproj", "{50D69AF5-F0B9-3136-8FCA-55FE6591433D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IOS.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\IOS\IOS.Automation.csproj", "{B4A8572E-927C-335A-AD94-643CE7EE8A25}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Linux.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Linux\Linux.Automation.csproj", "{945512E1-680F-3F80-85D4-E8A3723C632B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Localization.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Localization\Localization.Automation.csproj", "{F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LowLevelTests.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\LowLevelTests\LowLevelTests.Automation.csproj", "{A606EE4E-B01C-39FA-84A7-E1764EE70ABB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mac.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Mac\Mac.Automation.csproj", "{0D426AD6-872F-3381-BBB8-36F31135754F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneSkyLocalization.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\OneSkyLocalization\OneSkyLocalization.Automation.csproj", "{8E859816-E61A-3362-A45D-F10A4B262B0A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutomationScripts.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Scripts\AutomationScripts.Automation.csproj", "{BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartlingLocalization.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\SmartlingLocalization\SmartlingLocalization.Automation.csproj", "{1D036329-9024-3C18-9B2D-AA12DD087A69}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SteamDeck.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\SteamDeck\SteamDeck.Automation.csproj", "{9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TVOS.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\TVOS\TVOS.Automation.csproj", "{84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Turnkey.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Turnkey\Turnkey.Automation.csproj", "{226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\Win\Win.Automation.csproj", "{E94A506B-C605-3757-A1AC-000B38258BDB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XLocLocalization.Automation", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\AutomationTool\XLocLocalization\XLocLocalization.Automation.csproj", "{5F77975D-702D-322A-B309-2D2A3DA3C613}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.AspNet", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.AspNet\EpicGames.AspNet.csproj", "{3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Box", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Box\EpicGames.Box.csproj", "{0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Build", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Build\EpicGames.Build.csproj", "{E351FEDF-B2D7-3A80-AF0A-1828712D8D85}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.BuildGraph", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.BuildGraph\EpicGames.BuildGraph.csproj", "{93D7933D-7146-3347-8CBD-DA127EDF9731}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Core", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Core\EpicGames.Core.csproj", "{FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Horde", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Horde\EpicGames.Horde.csproj", "{74720E9C-7924-3709-8640-54BF3B653625}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.IoHash", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.IoHash\EpicGames.IoHash.csproj", "{F23644E6-7C7C-34DF-A22D-7D07131C3612}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Jupiter", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Jupiter\EpicGames.Jupiter.csproj", "{F5850976-1066-3555-82A8-78272F30F79D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.MongoDB", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.MongoDB\EpicGames.MongoDB.csproj", "{C7DA9F6F-B3BD-3E03-9403-B909C288EA81}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.MsBuild", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.MsBuild\EpicGames.MsBuild.csproj", "{161AD381-E40D-3846-BEFF-039447C2941B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.OIDC", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.OIDC\EpicGames.OIDC.csproj", "{0B8FA69A-672E-3241-9C74-911713ED3C35}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Oodle", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Oodle\EpicGames.Oodle.csproj", "{38526FC2-CFAA-341A-9C20-2733B936C846}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Perforce", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Perforce\EpicGames.Perforce.csproj", "{5A17B729-5B23-371E-BEE1-591788245F98}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Perforce.Fixture", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Perforce.Fixture\EpicGames.Perforce.Fixture.csproj", "{6CA5A4E4-4002-3354-B372-C714B9590CDC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Perforce.Managed", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Perforce.Managed\EpicGames.Perforce.Managed.csproj", "{8DA81558-7D97-3286-BC77-AB09F69EB2F2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Redis", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Redis\EpicGames.Redis.csproj", "{B0E1D002-785C-3E57-A52A-55C9D2363F2F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Serialization", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Serialization\EpicGames.Serialization.csproj", "{38F2CBC2-09BD-362E-9B8A-64F7201F7469}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Slack", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Slack\EpicGames.Slack.csproj", "{87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.Tracing", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.Tracing\EpicGames.Tracing.csproj", "{A29C994D-5BF5-3270-A08C-F6FBE1D311FF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicGames.UHT", "F:\Unreal Engine\Unreal Engine Source\Engine\Source\Programs\Shared\EpicGames.UHT\EpicGames.UHT.csproj", "{7FD7B508-3020-332E-9018-6869AF59AAC1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UE5ProgramRules", "F:\Unreal Engine\Unreal Engine Source\Engine\Intermediate\Build\BuildRulesProjects\UE5ProgramRules\UE5ProgramRules.csproj", "{78636179-9787-304E-86B8-B6CF6C527ABC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UE5Rules", "F:\Unreal Engine\Unreal Engine Source\Engine\Intermediate\Build\BuildRulesProjects\UE5Rules\UE5Rules.csproj", "{600DCEFD-7237-353D-AC38-EA07D8E4C673}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Visualizers", "Visualizers", "{1CCEC849-CC72-4C59-8C36-2F7C38706D4C}"
+ ProjectSection(SolutionItems) = preProject
+ F:\Unreal Engine\Unreal Engine Source\Engine\Extras\VisualStudioDebugging\Unreal.natvis = F:\Unreal Engine\Unreal Engine Source\Engine\Extras\VisualStudioDebugging\Unreal.natvis
+ F:\Unreal Engine\Unreal Engine Source\Engine\Extras\VisualStudioDebugging\Unreal.natstepfilter = F:\Unreal Engine\Unreal Engine Source\Engine\Extras\VisualStudioDebugging\Unreal.natstepfilter
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug Client|Win64 = Debug Client|Win64
+ Debug Editor|Win64 = Debug Editor|Win64
+ Debug Server|Win64 = Debug Server|Win64
+ DebugGame Client|Win64 = DebugGame Client|Win64
+ DebugGame Editor|Win64 = DebugGame Editor|Win64
+ DebugGame Server|Win64 = DebugGame Server|Win64
+ DebugGame|Win64 = DebugGame|Win64
+ Debug|Win64 = Debug|Win64
+ Development Client|Win64 = Development Client|Win64
+ Development Editor|Win64 = Development Editor|Win64
+ Development Server|Win64 = Development Server|Win64
+ Development|Win64 = Development|Win64
+ Shipping Client|Win64 = Shipping Client|Win64
+ Shipping Server|Win64 = Shipping Server|Win64
+ Shipping|Win64 = Shipping|Win64
+ Test Client|Win64 = Test Client|Win64
+ Test Server|Win64 = Test Server|Win64
+ Test|Win64 = Test|Win64
+ EndGlobalSection
+ # UnrealVS Section
+ GlobalSection(ddbf523f-7eb6-4887-bd51-85a714ff87eb) = preSolution
+ AvailablePlatforms=Win64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Debug Client|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Debug Editor|Win64.ActiveCfg = Debug_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Debug Editor|Win64.Build.0 = Debug_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Debug Server|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.DebugGame Client|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.DebugGame Editor|Win64.Build.0 = DebugGame_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.DebugGame Server|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.DebugGame|Win64.ActiveCfg = DebugGame_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.DebugGame|Win64.Build.0 = DebugGame_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Debug|Win64.ActiveCfg = Debug_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Debug|Win64.Build.0 = Debug_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Development Client|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Development Editor|Win64.ActiveCfg = Development_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Development Editor|Win64.Build.0 = Development_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Development Server|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Development|Win64.ActiveCfg = Development_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Development|Win64.Build.0 = Development_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Shipping Client|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Shipping Server|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Shipping|Win64.ActiveCfg = Shipping_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Shipping|Win64.Build.0 = Shipping_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Test Client|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Test Server|Win64.ActiveCfg = Invalid|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Test|Win64.ActiveCfg = Test_Program|x64
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D}.Test|Win64.Build.0 = Test_Program|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Debug Client|Win64.ActiveCfg = Debug_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Debug Client|Win64.Build.0 = Debug_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Debug Editor|Win64.ActiveCfg = Debug_Editor|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Debug Editor|Win64.Build.0 = Debug_Editor|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Debug Server|Win64.ActiveCfg = Debug_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Debug Server|Win64.Build.0 = Debug_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.DebugGame Client|Win64.ActiveCfg = DebugGame_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.DebugGame Client|Win64.Build.0 = DebugGame_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.DebugGame Server|Win64.ActiveCfg = DebugGame_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.DebugGame Server|Win64.Build.0 = DebugGame_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.DebugGame|Win64.ActiveCfg = DebugGame|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.DebugGame|Win64.Build.0 = DebugGame|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Debug|Win64.ActiveCfg = Debug|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Debug|Win64.Build.0 = Debug|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Development Client|Win64.ActiveCfg = Development_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Development Client|Win64.Build.0 = Development_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Development Editor|Win64.Build.0 = Development_Editor|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Development Server|Win64.ActiveCfg = Development_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Development Server|Win64.Build.0 = Development_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Development|Win64.ActiveCfg = Development|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Development|Win64.Build.0 = Development|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Shipping Client|Win64.ActiveCfg = Shipping_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Shipping Client|Win64.Build.0 = Shipping_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Shipping Server|Win64.ActiveCfg = Shipping_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Shipping Server|Win64.Build.0 = Shipping_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Shipping|Win64.ActiveCfg = Shipping|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Shipping|Win64.Build.0 = Shipping|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Test Client|Win64.ActiveCfg = Test_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Test Client|Win64.Build.0 = Test_Client|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Test Server|Win64.ActiveCfg = Test_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Test Server|Win64.Build.0 = Test_Server|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Test|Win64.ActiveCfg = Test|x64
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E}.Test|Win64.Build.0 = Test|x64
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Debug|Win64.Build.0 = Debug|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Development Client|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Development Server|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Development|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Development|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Shipping|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Test Client|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Test Server|Win64.Build.0 = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Test|Win64.ActiveCfg = Development|Any CPU
+ {F5380A68-9385-3B6D-A865-F65F23932F60}.Test|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Debug|Win64.Build.0 = Debug|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Development Client|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Development Server|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Development|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Development|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Shipping|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Test Client|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Test Server|Win64.Build.0 = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Test|Win64.ActiveCfg = Development|Any CPU
+ {E828FDF7-9B98-3750-9291-83F3881BB322}.Test|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Debug|Win64.Build.0 = Debug|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Development Client|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Development Server|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Development|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Development|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Shipping|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Test Client|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Test Server|Win64.Build.0 = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Test|Win64.ActiveCfg = Development|Any CPU
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030}.Test|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Debug|Win64.Build.0 = Debug|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Development Client|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Development Server|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Development|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Development|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Shipping|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Test Client|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Test Server|Win64.Build.0 = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Test|Win64.ActiveCfg = Development|Any CPU
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D}.Test|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Debug|Win64.Build.0 = Debug|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Development Client|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Development Server|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Development|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Development|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Shipping|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Test Client|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Test Server|Win64.Build.0 = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Test|Win64.ActiveCfg = Development|Any CPU
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5}.Test|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Debug|Win64.Build.0 = Debug|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Development Client|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Development Server|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Development|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Development|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Shipping|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Test Client|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Test Server|Win64.Build.0 = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Test|Win64.ActiveCfg = Development|Any CPU
+ {C8F75792-3814-3365-92CD-90A3E8A37A94}.Test|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Debug|Win64.Build.0 = Debug|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Development Client|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Development Server|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Development|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Development|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Shipping|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Test Client|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Test Server|Win64.Build.0 = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Test|Win64.ActiveCfg = Development|Any CPU
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62}.Test|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Debug|Win64.Build.0 = Debug|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Development Client|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Development Server|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Development|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Development|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Shipping|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Test Client|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Test Server|Win64.Build.0 = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Test|Win64.ActiveCfg = Development|Any CPU
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6}.Test|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Debug|Win64.Build.0 = Debug|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Development Client|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Development Server|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Development|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Development|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Shipping|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Test Client|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Test Server|Win64.Build.0 = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Test|Win64.ActiveCfg = Development|Any CPU
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D}.Test|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Debug|Win64.Build.0 = Debug|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Development Client|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Development Server|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Development|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Development|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Shipping|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Test Client|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Test Server|Win64.Build.0 = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Test|Win64.ActiveCfg = Development|Any CPU
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25}.Test|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Debug|Win64.Build.0 = Debug|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Development Client|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Development Server|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Development|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Development|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Shipping|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Test Client|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Test Server|Win64.Build.0 = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Test|Win64.ActiveCfg = Development|Any CPU
+ {945512E1-680F-3F80-85D4-E8A3723C632B}.Test|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Debug|Win64.Build.0 = Debug|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Development Client|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Development Server|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Development|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Development|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Shipping|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Test Client|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Test Server|Win64.Build.0 = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Test|Win64.ActiveCfg = Development|Any CPU
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD}.Test|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Debug|Win64.Build.0 = Debug|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Development Client|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Development Server|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Development|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Development|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Shipping|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Test Client|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Test Server|Win64.Build.0 = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Test|Win64.ActiveCfg = Development|Any CPU
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB}.Test|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Debug|Win64.Build.0 = Debug|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Development Client|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Development Server|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Development|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Development|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Shipping|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Test Client|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Test Server|Win64.Build.0 = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Test|Win64.ActiveCfg = Development|Any CPU
+ {0D426AD6-872F-3381-BBB8-36F31135754F}.Test|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Debug|Win64.Build.0 = Debug|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Development Client|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Development Server|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Development|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Development|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Shipping|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Test Client|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Test Server|Win64.Build.0 = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Test|Win64.ActiveCfg = Development|Any CPU
+ {8E859816-E61A-3362-A45D-F10A4B262B0A}.Test|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Debug|Win64.Build.0 = Debug|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Development Client|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Development Server|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Development|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Development|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Shipping|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Test Client|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Test Server|Win64.Build.0 = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Test|Win64.ActiveCfg = Development|Any CPU
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D}.Test|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Debug|Win64.Build.0 = Debug|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Development Client|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Development Server|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Development|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Development|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Shipping|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Test Client|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Test Server|Win64.Build.0 = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Test|Win64.ActiveCfg = Development|Any CPU
+ {1D036329-9024-3C18-9B2D-AA12DD087A69}.Test|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Debug|Win64.Build.0 = Debug|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Development Client|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Development Server|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Development|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Development|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Shipping|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Test Client|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Test Server|Win64.Build.0 = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Test|Win64.ActiveCfg = Development|Any CPU
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD}.Test|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Debug|Win64.Build.0 = Debug|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Development Client|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Development Server|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Development|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Development|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Shipping|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Test Client|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Test Server|Win64.Build.0 = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Test|Win64.ActiveCfg = Development|Any CPU
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2}.Test|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Debug|Win64.Build.0 = Debug|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Development Client|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Development Server|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Development|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Development|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Shipping|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Test Client|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Test Server|Win64.Build.0 = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Test|Win64.ActiveCfg = Development|Any CPU
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D}.Test|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Debug|Win64.Build.0 = Debug|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Development Client|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Development Server|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Development|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Development|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Shipping|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Test Client|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Test Server|Win64.Build.0 = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Test|Win64.ActiveCfg = Development|Any CPU
+ {E94A506B-C605-3757-A1AC-000B38258BDB}.Test|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Debug|Win64.Build.0 = Debug|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Development Client|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Development Server|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Development|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Development|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Shipping|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Test Client|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Test Server|Win64.Build.0 = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Test|Win64.ActiveCfg = Development|Any CPU
+ {5F77975D-702D-322A-B309-2D2A3DA3C613}.Test|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Debug|Win64.Build.0 = Debug|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Development Client|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Development Server|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Development|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Development|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Shipping|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Test Client|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Test Server|Win64.Build.0 = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Test|Win64.ActiveCfg = Development|Any CPU
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789}.Test|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Debug|Win64.Build.0 = Debug|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Development Client|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Development Server|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Development|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Development|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Shipping|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Test Client|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Test Server|Win64.Build.0 = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Test|Win64.ActiveCfg = Development|Any CPU
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B}.Test|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Debug|Win64.Build.0 = Debug|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Development Client|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Development Server|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Development|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Development|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Shipping|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Test Client|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Test Server|Win64.Build.0 = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Test|Win64.ActiveCfg = Development|Any CPU
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85}.Test|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Debug|Win64.Build.0 = Debug|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Development Client|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Development Server|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Development|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Development|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Shipping|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Test Client|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Test Server|Win64.Build.0 = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Test|Win64.ActiveCfg = Development|Any CPU
+ {93D7933D-7146-3347-8CBD-DA127EDF9731}.Test|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Debug|Win64.Build.0 = Debug|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Development Client|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Development Server|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Development|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Development|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Shipping|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Test Client|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Test Server|Win64.Build.0 = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Test|Win64.ActiveCfg = Development|Any CPU
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD}.Test|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Debug|Win64.Build.0 = Debug|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Development Client|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Development Server|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Development|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Development|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Shipping|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Test Client|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Test Server|Win64.Build.0 = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Test|Win64.ActiveCfg = Development|Any CPU
+ {74720E9C-7924-3709-8640-54BF3B653625}.Test|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Debug|Win64.Build.0 = Debug|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Development Client|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Development Server|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Development|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Development|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Shipping|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Test Client|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Test Server|Win64.Build.0 = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Test|Win64.ActiveCfg = Development|Any CPU
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612}.Test|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Debug|Win64.Build.0 = Debug|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Development Client|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Development Server|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Development|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Development|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Shipping|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Test Client|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Test Server|Win64.Build.0 = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Test|Win64.ActiveCfg = Development|Any CPU
+ {F5850976-1066-3555-82A8-78272F30F79D}.Test|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Debug|Win64.Build.0 = Debug|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Development Client|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Development Server|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Development|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Development|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Shipping|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Test Client|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Test Server|Win64.Build.0 = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Test|Win64.ActiveCfg = Development|Any CPU
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81}.Test|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Debug|Win64.Build.0 = Debug|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Development Client|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Development Server|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Development|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Development|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Shipping|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Test Client|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Test Server|Win64.Build.0 = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Test|Win64.ActiveCfg = Development|Any CPU
+ {161AD381-E40D-3846-BEFF-039447C2941B}.Test|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Debug|Win64.Build.0 = Debug|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Development Client|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Development Server|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Development|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Development|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Shipping|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Test Client|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Test Server|Win64.Build.0 = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Test|Win64.ActiveCfg = Development|Any CPU
+ {0B8FA69A-672E-3241-9C74-911713ED3C35}.Test|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Debug|Win64.Build.0 = Debug|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Development Client|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Development Server|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Development|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Development|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Shipping|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Test Client|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Test Server|Win64.Build.0 = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Test|Win64.ActiveCfg = Development|Any CPU
+ {38526FC2-CFAA-341A-9C20-2733B936C846}.Test|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Debug|Win64.Build.0 = Debug|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Development Client|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Development Server|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Development|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Development|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Shipping|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Test Client|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Test Server|Win64.Build.0 = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Test|Win64.ActiveCfg = Development|Any CPU
+ {5A17B729-5B23-371E-BEE1-591788245F98}.Test|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Debug|Win64.Build.0 = Debug|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Development Client|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Development Server|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Development|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Development|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Shipping|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Test Client|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Test Server|Win64.Build.0 = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Test|Win64.ActiveCfg = Development|Any CPU
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC}.Test|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Debug|Win64.Build.0 = Debug|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Development Client|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Development Server|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Development|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Development|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Shipping|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Test Client|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Test Server|Win64.Build.0 = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Test|Win64.ActiveCfg = Development|Any CPU
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2}.Test|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Debug|Win64.Build.0 = Debug|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Development Client|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Development Server|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Development|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Development|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Shipping|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Test Client|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Test Server|Win64.Build.0 = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Test|Win64.ActiveCfg = Development|Any CPU
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F}.Test|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Debug|Win64.Build.0 = Debug|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Development Client|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Development Server|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Development|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Development|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Shipping|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Test Client|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Test Server|Win64.Build.0 = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Test|Win64.ActiveCfg = Development|Any CPU
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469}.Test|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Debug|Win64.Build.0 = Debug|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Development Client|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Development Server|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Development|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Development|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Shipping|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Test Client|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Test Server|Win64.Build.0 = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Test|Win64.ActiveCfg = Development|Any CPU
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4}.Test|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Debug|Win64.Build.0 = Debug|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Development Client|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Development Server|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Development|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Development|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Shipping|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Test Client|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Test Server|Win64.Build.0 = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Test|Win64.ActiveCfg = Development|Any CPU
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF}.Test|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Debug|Win64.Build.0 = Debug|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Development Client|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Development Server|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Development|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Development|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Shipping|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Test Client|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Test Server|Win64.Build.0 = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Test|Win64.ActiveCfg = Development|Any CPU
+ {7FD7B508-3020-332E-9018-6869AF59AAC1}.Test|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Debug|Win64.Build.0 = Debug|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Development Client|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Development Server|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Development|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Development|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Shipping|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Test Client|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Test Server|Win64.Build.0 = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Test|Win64.ActiveCfg = Development|Any CPU
+ {78636179-9787-304E-86B8-B6CF6C527ABC}.Test|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Debug Client|Win64.ActiveCfg = Debug|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Debug Client|Win64.Build.0 = Debug|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Debug Editor|Win64.ActiveCfg = Debug|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Debug Editor|Win64.Build.0 = Debug|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Debug Server|Win64.ActiveCfg = Debug|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Debug Server|Win64.Build.0 = Debug|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.DebugGame Client|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.DebugGame Client|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.DebugGame Editor|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.DebugGame Editor|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.DebugGame Server|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.DebugGame Server|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.DebugGame|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.DebugGame|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Debug|Win64.ActiveCfg = Debug|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Debug|Win64.Build.0 = Debug|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Development Client|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Development Client|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Development Editor|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Development Editor|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Development Server|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Development Server|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Development|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Development|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Shipping Client|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Shipping Client|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Shipping Server|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Shipping Server|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Shipping|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Shipping|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Test Client|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Test Client|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Test Server|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Test Server|Win64.Build.0 = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Test|Win64.ActiveCfg = Development|Any CPU
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673}.Test|Win64.Build.0 = Development|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {FA3A9BFD-38DB-3C07-8F0C-5F318D319F6E} = {233774A8-CC9D-3FA9-86D1-90573E92B704}
+ {BCB27524-99E9-3ED5-A46C-9B2A4C9E616D} = {A338B9E2-A559-34BE-A46D-F789DD488FAD}
+ {F5380A68-9385-3B6D-A865-F65F23932F60} = {A338B9E2-A559-34BE-A46D-F789DD488FAD}
+ {E828FDF7-9B98-3750-9291-83F3881BB322} = {A338B9E2-A559-34BE-A46D-F789DD488FAD}
+ {0BFBE63A-B98A-3411-8EEB-8918FEC737B3} = {A338B9E2-A559-34BE-A46D-F789DD488FAD}
+ {57713676-9DBE-331C-AD10-26632AC9EE0C} = {A338B9E2-A559-34BE-A46D-F789DD488FAD}
+ {87526EDE-1DA3-3AD7-AD70-4F86F3A6A030} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {351A56DD-47EF-3C72-88C7-E8D454E0D53D} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {60768F89-46FE-3C70-9D7C-9DFF15015AD5} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {C8F75792-3814-3365-92CD-90A3E8A37A94} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {8AC5B9E6-06F5-3FDC-BA1D-A7D794B12F62} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {A338EC7C-9C0B-3113-904A-777A3EDEC8B6} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {50D69AF5-F0B9-3136-8FCA-55FE6591433D} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {B4A8572E-927C-335A-AD94-643CE7EE8A25} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {945512E1-680F-3F80-85D4-E8A3723C632B} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {F8787EF8-E9B1-3AE2-B6C5-B8FF104297FD} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {A606EE4E-B01C-39FA-84A7-E1764EE70ABB} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {0D426AD6-872F-3381-BBB8-36F31135754F} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {8E859816-E61A-3362-A45D-F10A4B262B0A} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {BE55092C-F7FA-3440-ACA0-0A9EAACA1B3D} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {1D036329-9024-3C18-9B2D-AA12DD087A69} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {9C39E0C9-7A3C-3759-B1CC-53D84FC305CD} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {84B9C45A-CBCC-3795-BA19-1644B6A2DBA2} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {226BFEDB-ABEB-3F8C-AF2E-97E05AA8168D} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {E94A506B-C605-3757-A1AC-000B38258BDB} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {5F77975D-702D-322A-B309-2D2A3DA3C613} = {0BFBE63A-B98A-3411-8EEB-8918FEC737B3}
+ {3C72C513-DA89-3CA7-9D52-FE1FE6EA2789} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {0BAD26A6-E5B6-38CD-AF56-CD07362FFE8B} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {E351FEDF-B2D7-3A80-AF0A-1828712D8D85} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {93D7933D-7146-3347-8CBD-DA127EDF9731} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {FEA8B339-AD24-3CA2-92CD-DDFB30EBD1DD} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {74720E9C-7924-3709-8640-54BF3B653625} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {F23644E6-7C7C-34DF-A22D-7D07131C3612} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {F5850976-1066-3555-82A8-78272F30F79D} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {C7DA9F6F-B3BD-3E03-9403-B909C288EA81} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {161AD381-E40D-3846-BEFF-039447C2941B} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {0B8FA69A-672E-3241-9C74-911713ED3C35} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {38526FC2-CFAA-341A-9C20-2733B936C846} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {5A17B729-5B23-371E-BEE1-591788245F98} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {6CA5A4E4-4002-3354-B372-C714B9590CDC} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {8DA81558-7D97-3286-BC77-AB09F69EB2F2} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {B0E1D002-785C-3E57-A52A-55C9D2363F2F} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {38F2CBC2-09BD-362E-9B8A-64F7201F7469} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {87EA79BD-2651-38F6-9DBF-D8A045FEC9F4} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {A29C994D-5BF5-3270-A08C-F6FBE1D311FF} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {7FD7B508-3020-332E-9018-6869AF59AAC1} = {57713676-9DBE-331C-AD10-26632AC9EE0C}
+ {78636179-9787-304E-86B8-B6CF6C527ABC} = {C2F57ECE-B26F-39D8-BDA7-C1D40BD8F180}
+ {600DCEFD-7237-353D-AC38-EA07D8E4C673} = {C2F57ECE-B26F-39D8-BDA7-C1D40BD8F180}
+ EndGlobalSection
+EndGlobal
diff --git a/Arona.sln.DotSettings.user b/Arona.sln.DotSettings.user
new file mode 100644
index 0000000..fe1d664
--- /dev/null
+++ b/Arona.sln.DotSettings.user
@@ -0,0 +1,3 @@
+
+ ForceIncluded
+ ForceIncluded
\ No newline at end of file
diff --git a/Arona.uproject b/Arona.uproject
new file mode 100644
index 0000000..2a2f2d5
--- /dev/null
+++ b/Arona.uproject
@@ -0,0 +1,18 @@
+{
+ "FileVersion": 3,
+ "EngineAssociation": "{15DECA3A-4D95-597C-AAD4-38A8F659756E}",
+ "Category": "",
+ "Description": "",
+ "Modules": [
+ {
+ "Name": "Arona",
+ "Type": "Runtime",
+ "LoadingPhase": "Default"
+ },
+ {
+ "Name": "AronaModule",
+ "Type": "Runtime",
+ "LoadingPhase": "Default"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Config/AronaSettings.ini b/Config/AronaSettings.ini
new file mode 100644
index 0000000..b76effd
--- /dev/null
+++ b/Config/AronaSettings.ini
@@ -0,0 +1,2 @@
+[Skin]
+Skin=Default
\ No newline at end of file
diff --git a/Content/Shader/Arona/D3D/Test.hlsl b/Content/Shader/Arona/D3D/Test.hlsl
new file mode 100644
index 0000000..c07e60f
--- /dev/null
+++ b/Content/Shader/Arona/D3D/Test.hlsl
@@ -0,0 +1,31 @@
+
+// Texture2D WaveformTexture;
+// SamplerState WaveformTextureSampler;
+
+struct VertexOut
+{
+ float4 Position : SV_POSITION;
+ float4 Color : COLOR0;
+ float4 SecondaryColor : COLOR1;
+ float4 TextureCoordinates : TEXCOORD0;
+};
+
+
+float4 Main(VertexOut InVertex) : SV_Target
+{
+ // float4 WaveformData = WaveformTexture.Sample(WaveformTextureSampler, InVertex.TextureCoordinates.xy * InVertex.TextureCoordinates.zw);
+
+ // float4 Color;
+ // float Top = WaveformData.r;
+ // float Buttom = WaveformData.g;
+
+ // if(InVertex.TextureCoordinates.y >= Buttom && InVertex.TextureCoordinates.y <= Top)
+ // {
+ // Color = float4(0, 1, 0, 1);
+ // }
+ // else
+ // {
+ // Color = float4(0, 0, 0, 0);
+ // }
+ return InVertex.TextureCoordinates;
+}
diff --git a/Content/Shader/Arona/D3D/WaveformCS.hlsl b/Content/Shader/Arona/D3D/WaveformCS.hlsl
new file mode 100644
index 0000000..b16451a
--- /dev/null
+++ b/Content/Shader/Arona/D3D/WaveformCS.hlsl
@@ -0,0 +1,42 @@
+RWTexture2D Result;
+RWStructuredBuffer Samples;
+cbuffer Params : register(b0)
+{
+ float4 WaveColor;
+ float4 BgColor;
+ float LineUV;
+};
+
+[numthreads(1, 1, 1)]
+void Main(uint3 id : SV_DispatchThreadID)
+{
+ uint width, height;
+ Result.GetDimensions(width, height);
+
+ // float2 uv = float2(id.xy / float2(width, height));
+ // uv.y = abs(((1.0 - uv.y) - 0.5) * 2); // 居中
+
+ int X = id.x;
+ int Y = id.y;
+
+ // float4 color = lerp(BgColor, WaveColor, min(step(value.x, uv.y), step(uv.y , value.y)));
+
+ float Top = Samples[X * 2] + 1; // -1;
+ float Bottom = Samples[X * 2 + 1] + 1; // 1;
+ Top = min(Top, 1);
+ Bottom = max(Bottom, 0);
+ Top *= height;
+ Top *= 0.5;
+ Bottom *= height;
+ Bottom *= 0.5;
+
+
+ if ((id.y <= Bottom && id.y >= Top) || (Y == height / 2))
+ {
+ Result[id.xy] = WaveColor;
+ }
+ else
+ {
+ Result[id.xy] = BgColor;
+ }
+}
\ No newline at end of file
diff --git a/Content/Shader/Arona/OpenGL/Test.glsl b/Content/Shader/Arona/OpenGL/Test.glsl
new file mode 100644
index 0000000..35db2b2
--- /dev/null
+++ b/Content/Shader/Arona/OpenGL/Test.glsl
@@ -0,0 +1,23 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+// handle differences between ES and full GL shaders
+#if PLATFORM_USES_GLES
+precision highp float;
+#else
+// #version 120 at the beginning is added in FSlateOpenGLShader::CompileShader()
+#extension GL_EXT_gpu_shader4 : enable
+#endif
+
+// uniform sampler2D WaveformTexture;
+
+in vec4 Position;
+in vec4 TexCoords;
+in vec4 Color;
+in vec4 SecondaryColor;
+out vec4 fragColor;
+void main()
+{
+ vec4 OutColor = vec4(0.262,1.000,0.217,1.000);
+ // gl_FragColor = texture2D(WaveformTexture, TexCoords.xy);
+ fragColor = TexCoords;
+}
diff --git a/Content/Shader/Arona/OpenGL/WaveformCS.glsl b/Content/Shader/Arona/OpenGL/WaveformCS.glsl
new file mode 100644
index 0000000..81a3904
--- /dev/null
+++ b/Content/Shader/Arona/OpenGL/WaveformCS.glsl
@@ -0,0 +1,56 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+// handle differences between ES and full GL shaders
+#if PLATFORM_USES_GLES
+precision highp float;
+#else
+// #version 120 at the beginning is added in FSlateOpenGLShader::CompileShader()
+#extension GL_EXT_gpu_shader4 : enable
+#endif
+layout (local_size_x = 1,local_size_y = 1,local_size_z = 1) in;
+
+vec4 lerp(vec4 a, vec4 b, float x)
+{
+ return a + x * (b - a);
+}
+
+
+layout (rgba8, binding = 2) writeonly uniform image2D Result;
+layout (std430, binding = 0) buffer Samples
+{
+ float AudioSamples[];
+};
+layout (std430, binding = 1) buffer Params
+{
+ vec4 WaveColor;
+ vec4 BgColor;
+ float LineUV;
+};
+
+void main()
+{
+ vec2 size = vec2(imageSize(Result));
+ ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
+
+ int X = pos.x;
+ int Y = pos.y;
+
+ float height = size.y;
+ float Top = AudioSamples[X * 2] + 1; // -1;
+ float Bottom = AudioSamples[X * 2 + 1] + 1; // 1;
+ Top = min(Top, 1);
+ Bottom = max(Bottom, 0);
+ Top *= height;
+ Top *= 0.5;
+ Bottom *= height;
+ Bottom *= 0.5;
+
+ if ((Y <= Bottom && Y >= Top) || (Y == int(height / 2)))
+ {
+ imageStore(Result, pos, WaveColor);
+ }
+ else
+ {
+ imageStore(Result, pos, BgColor);
+ }
+}
diff --git a/Content/Shader/StandaloneRenderer/D3D/GammaCorrectionCommon.hlsl b/Content/Shader/StandaloneRenderer/D3D/GammaCorrectionCommon.hlsl
new file mode 100644
index 0000000..26cfdca
--- /dev/null
+++ b/Content/Shader/StandaloneRenderer/D3D/GammaCorrectionCommon.hlsl
@@ -0,0 +1,59 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+
+half3 LinearTo709Branchless(half3 lin)
+{
+ lin = max(6.10352e-5, lin); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
+ return min(lin * 4.5, pow(max(lin, 0.018), 0.45) * 1.099 - 0.099);
+}
+
+half3 LinearToSrgbBranchless(half3 lin)
+{
+ lin = max(6.10352e-5, lin); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
+ return min(lin * 12.92, pow(max(lin, 0.00313067), 1.0/2.4) * 1.055 - 0.055);
+ // Possible that mobile GPUs might have native pow() function?
+ //return min(lin * 12.92, exp2(log2(max(lin, 0.00313067)) * (1.0/2.4) + log2(1.055)) - 0.055);
+}
+
+half LinearToSrgbBranchingChannel(half lin)
+{
+ if(lin < 0.00313067) return lin * 12.92;
+ return pow(lin, (1.0/2.4)) * 1.055 - 0.055;
+}
+
+half3 LinearToSrgbBranching(half3 lin)
+{
+ return half3(
+ LinearToSrgbBranchingChannel(lin.r),
+ LinearToSrgbBranchingChannel(lin.g),
+ LinearToSrgbBranchingChannel(lin.b));
+}
+
+half3 sRGBToLinear( half3 Color )
+{
+ Color = max(6.10352e-5, Color); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
+ return Color > 0.04045 ? pow( Color * (1.0 / 1.055) + 0.0521327, 2.4 ) : Color * (1.0 / 12.92);
+}
+
+/**
+ * @param GammaCurveRatio The curve ratio compared to a 2.2 standard gamma, e.g. 2.2 / DisplayGamma. So normally the value is 1.
+ */
+half3 ApplyGammaCorrection(float3 LinearColor, float GammaCurveRatio)
+{
+ // Apply "gamma" curve adjustment.
+ float3 CorrectedColor = pow(LinearColor, GammaCurveRatio);
+
+ #if MAC
+ // Note, MacOSX native output is raw gamma 2.2 not sRGB!
+ CorrectedColor = pow(CorrectedColor, 1.0/2.2);
+ #else
+ #if USE_709
+ // Didn't profile yet if the branching version would be faster (different linear segment).
+ CorrectedColor = LinearTo709Branchless(CorrectedColor);
+ #else
+ CorrectedColor = LinearToSrgbBranching(CorrectedColor);
+ #endif
+ #endif
+
+ return CorrectedColor;
+}
\ No newline at end of file
diff --git a/Content/Shader/StandaloneRenderer/D3D/SlateDefaultVertexShader.hlsl b/Content/Shader/StandaloneRenderer/D3D/SlateDefaultVertexShader.hlsl
new file mode 100644
index 0000000..93917bf
--- /dev/null
+++ b/Content/Shader/StandaloneRenderer/D3D/SlateDefaultVertexShader.hlsl
@@ -0,0 +1,39 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "GammaCorrectionCommon.hlsl"
+
+cbuffer PerElementVSConstants
+{
+ matrix WorldViewProjection;
+}
+
+struct VertexOut
+{
+ float4 Position : SV_POSITION;
+ float4 Color : COLOR0;
+ float4 SecondaryColor : COLOR1;
+ float4 TextureCoordinates : TEXCOORD0;
+};
+
+VertexOut Main(
+ in float2 InPosition : POSITION,
+ in float4 InTextureCoordinates : TEXCOORD0,
+ in float2 MaterialTexCoords : TEXCOORD1,
+ in float4 InColor : COLOR0,
+ in float4 InSecondaryColor : COLOR1
+ )
+{
+ VertexOut Out;
+
+ Out.Position = mul( WorldViewProjection, float4( InPosition.xy, 0, 1 ) );
+
+ Out.TextureCoordinates = InTextureCoordinates;
+
+ InColor.rgb = sRGBToLinear(InColor.rgb);
+ InSecondaryColor.rgb = sRGBToLinear(InSecondaryColor.rgb);
+
+ Out.Color = InColor;
+ Out.SecondaryColor = InSecondaryColor;
+
+ return Out;
+}
diff --git a/Content/Shader/StandaloneRenderer/D3D/SlateElementPixelShader.hlsl b/Content/Shader/StandaloneRenderer/D3D/SlateElementPixelShader.hlsl
new file mode 100644
index 0000000..99bc967
--- /dev/null
+++ b/Content/Shader/StandaloneRenderer/D3D/SlateElementPixelShader.hlsl
@@ -0,0 +1,269 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "GammaCorrectionCommon.hlsl"
+
+// Shader types
+#define ESlateShader::Default 0
+#define ESlateShader::Border 1
+#define ESlateShader::GrayscaleFont 2
+#define ESlateShader::ColorFont 3
+#define ESlateShader::LineSegment 4
+#define ESlateShader::PostProcess 6
+#define ESlateShader::RoundedBox 7
+
+#define USE_LEGACY_DISABLED_EFFECT 0
+
+Texture2D ElementTexture;
+SamplerState ElementTextureSampler;
+
+cbuffer PerFramePSConstants
+{
+ /** Display gamma x:gamma curve adjustment, y:inverse gamma (1/GEngine->DisplayGamma) */
+ float2 GammaValues;
+};
+
+cbuffer PerElementPSConstants
+{
+ float4 ShaderParams; // 16 bytes
+ float4 ShaderParams2; // 16 bytes
+ uint ShaderType; // 4 bytes
+ uint IgnoreTextureAlpha; // 4 bytes
+ uint DisableEffect; // 4 bytes
+ uint UNUSED[1]; // 4 bytes
+};
+
+struct VertexOut
+{
+ float4 Position : SV_POSITION;
+ float4 Color : COLOR0;
+ float4 SecondaryColor : COLOR1;
+ float4 TextureCoordinates : TEXCOORD0;
+};
+
+float3 Hue( float H )
+{
+ float R = abs(H * 6 - 3) - 1;
+ float G = 2 - abs(H * 6 - 2);
+ float B = 2 - abs(H * 6 - 4);
+ return saturate( float3(R,G,B) );
+}
+
+float3 GammaCorrect(float3 InColor)
+{
+ float3 CorrectedColor = InColor;
+
+ if ( GammaValues.y != 1.0f )
+ {
+ CorrectedColor = ApplyGammaCorrection(CorrectedColor, GammaValues.x);
+ }
+
+ return CorrectedColor;
+}
+
+float4 GetGrayscaleFontElementColor( VertexOut InVertex )
+{
+ float4 OutColor = InVertex.Color;
+
+ OutColor.a *= ElementTexture.Sample(ElementTextureSampler, InVertex.TextureCoordinates.xy).a;
+
+ return OutColor;
+}
+
+float4 GetColorFontElementColor(VertexOut InVertex)
+{
+ float4 OutColor = InVertex.Color;
+
+ OutColor *= ElementTexture.Sample(ElementTextureSampler, InVertex.TextureCoordinates.xy);
+
+ return OutColor;
+}
+
+float4 GetColor( VertexOut InVertex, float2 UV )
+{
+ float4 FinalColor;
+
+ float4 BaseColor = ElementTexture.Sample(ElementTextureSampler, UV );
+ if( IgnoreTextureAlpha != 0 )
+ {
+ BaseColor.a = 1.0f;
+ }
+
+ FinalColor = BaseColor*InVertex.Color;
+ return FinalColor;
+}
+
+float4 GetDefaultElementColor( VertexOut InVertex )
+{
+ return GetColor( InVertex, InVertex.TextureCoordinates.xy*InVertex.TextureCoordinates.zw );
+}
+
+float4 GetBorderElementColor( VertexOut InVertex )
+{
+ float2 NewUV;
+ if( InVertex.TextureCoordinates.z == 0.0f && InVertex.TextureCoordinates.w == 0.0f )
+ {
+ NewUV = InVertex.TextureCoordinates.xy;
+ }
+ else
+ {
+ float2 MinUV;
+ float2 MaxUV;
+
+ if( InVertex.TextureCoordinates.z > 0 )
+ {
+ MinUV = float2(ShaderParams.x,0);
+ MaxUV = float2(ShaderParams.y,1);
+ InVertex.TextureCoordinates.w = 1.0f;
+ }
+ else
+ {
+ MinUV = float2(0,ShaderParams.z);
+ MaxUV = float2(1,ShaderParams.w);
+ InVertex.TextureCoordinates.z = 1.0f;
+ }
+
+ NewUV = InVertex.TextureCoordinates.xy*InVertex.TextureCoordinates.zw;
+ NewUV = frac(NewUV);
+ NewUV = lerp(MinUV,MaxUV,NewUV);
+ }
+
+ return GetColor( InVertex, NewUV );
+}
+
+float GetRoundedBoxDistance(float2 pos, float2 center, float radius, float inset)
+{
+ // distance from center
+ pos = abs(pos - center);
+
+ // distance from the inner corner
+ pos = pos - (center - float2(radius + inset, radius + inset));
+
+ // use distance to nearest edge when not in quadrant with radius
+ // this handles an edge case when radius is very close to thickness
+ // otherwise we're in the quadrant with the radius,
+ // just use the analytic signed distance function
+ return lerp( length(pos) - radius, max(pos.x - radius, pos.y - radius), float(pos.x <= 0 || pos.y <=0) );
+}
+
+float4 GetRoundedBoxElementColor( VertexOut InVertex )
+{
+ const float2 size = ShaderParams.zw;
+ float2 pos = size * InVertex.TextureCoordinates.xy;
+ float2 center = size / 2.0;
+
+ //X = Top Left, Y = Top Right, Z = Bottom Right, W = Bottom Left */
+ float4 cornerRadii = ShaderParams2;
+
+ // figure out which radius to use based on which quadrant we're in
+ float2 quadrant = step(InVertex.TextureCoordinates.xy, float2(.5,.5));
+
+ float left = lerp(cornerRadii.y, cornerRadii.x, quadrant.x);
+ float right = lerp(cornerRadii.z, cornerRadii.w, quadrant.x);
+ float radius = lerp(right, left, quadrant.y);
+
+ float thickness = ShaderParams.y;
+
+ // Compute the distances internal and external to the border outline
+ float dext = GetRoundedBoxDistance(pos, center, radius, 0.0);
+ float din = GetRoundedBoxDistance(pos, center, max(radius - thickness, 0), thickness);
+
+ // Compute the border intensity and fill intensity with a smooth transition
+ float spread = 0.5;
+ float bi = smoothstep(spread, -spread, dext);
+ float fi = smoothstep(spread, -spread, din);
+
+ // alpha blend the external color
+ float4 fill = GetColor(InVertex, InVertex.TextureCoordinates.xy * InVertex.TextureCoordinates.zw);
+ float4 border = InVertex.SecondaryColor;
+ float4 OutColor = lerp(border, fill, float(thickness > radius));
+ OutColor.a = 0.0;
+
+ // blend in the border and fill colors
+ OutColor = lerp(OutColor, border, bi);
+ OutColor = lerp(OutColor, fill, fi);
+ return OutColor;
+}
+
+float4 GetLineSegmentElementColor( VertexOut InVertex )
+{
+ const float2 Gradient = InVertex.TextureCoordinates;
+
+ const float2 OutsideFilterUV = float2(1.0f, 1.0f);
+ const float2 InsideFilterUV = float2(ShaderParams.x, 0.0f);
+ const float2 LineCoverage = smoothstep(OutsideFilterUV, InsideFilterUV, abs(Gradient));
+
+ float4 Color = InVertex.Color;
+ Color.a *= LineCoverage.x * LineCoverage.y;
+ return Color;
+}
+
+float PseudoRandom(float2 xy)
+{
+ float2 pos = frac(xy / 128.0f) * 128.0f + float2(-64.340622f, -72.465622f);
+
+ // found by experimentation
+ return frac(dot(pos.xyx * pos.xyy, float3(20.390625f, 60.703125f, 2.4281209f)));
+}
+
+float4 GetPostProcessColor( VertexOut InVertex )
+{
+ return InVertex.Color;
+}
+
+float4 Main( VertexOut InVertex ) : SV_Target
+{
+ float4 OutColor;
+
+ if( ShaderType == ESlateShader::Default )
+ {
+ OutColor = GetDefaultElementColor( InVertex );
+ }
+ else if( ShaderType == ESlateShader::RoundedBox)
+ {
+ OutColor = GetRoundedBoxElementColor( InVertex );
+ }
+ else if( ShaderType == ESlateShader::Border )
+ {
+ OutColor = GetBorderElementColor( InVertex );
+ }
+ else if( ShaderType == ESlateShader::GrayscaleFont )
+ {
+ OutColor = GetGrayscaleFontElementColor( InVertex );
+ }
+ else if (ShaderType == ESlateShader::ColorFont)
+ {
+ OutColor = GetColorFontElementColor(InVertex);
+ }
+ else if (ShaderType == ESlateShader::PostProcess)
+ {
+ OutColor = GetPostProcessColor(InVertex);
+ }
+ else
+ {
+ OutColor = GetLineSegmentElementColor( InVertex );
+ }
+
+ // gamma correct
+ OutColor.rgb = GammaCorrect(OutColor.rgb);
+
+ if (DisableEffect)
+ {
+#if USE_LEGACY_DISABLED_EFFECT
+
+ //desaturate
+ float3 LumCoeffs = float3( 0.3, 0.59, .11 );
+ float Lum = dot( LumCoeffs, OutColor.rgb );
+ OutColor.rgb = lerp( OutColor.rgb, float3(Lum,Lum,Lum), .8 );
+
+ float3 Grayish = {.4, .4, .4};
+
+ // lerp between desaturated color and gray color based on distance from the desaturated color to the gray
+ OutColor.rgb = lerp( OutColor.rgb, Grayish, clamp( distance( OutColor.rgb, Grayish ), 0, .8) );
+#else
+ OutColor.a *= .45f;
+#endif
+ }
+
+ return OutColor;
+}
+
diff --git a/Content/Shader/StandaloneRenderer/OpenGL/SlateDefaultVertexShader.glsl b/Content/Shader/StandaloneRenderer/OpenGL/SlateDefaultVertexShader.glsl
new file mode 100644
index 0000000..0b6f3af
--- /dev/null
+++ b/Content/Shader/StandaloneRenderer/OpenGL/SlateDefaultVertexShader.glsl
@@ -0,0 +1,50 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+// #version 120 at the beginning is added in FSlateOpenGLShader::CompileShader()
+
+uniform mat4 ViewProjectionMatrix;
+
+// Per vertex
+in vec4 InTexCoords;
+in vec2 InPosition;
+in vec4 InColor;
+in vec4 InSecondaryColor;
+
+// Between vertex and pixel shader
+out vec4 Position;
+out vec4 TexCoords;
+out vec4 Color;
+out vec4 SecondaryColor;
+
+vec3 powScalar(vec3 values, float power)
+{
+ return vec3(pow(values.x, power), pow(values.y, power), pow(values.z, power));
+}
+
+float sRGBToLinearChannel( float ColorChannel )
+{
+ return ColorChannel > 0.04045 ? pow( ColorChannel * (1.0 / 1.055) + 0.0521327, 2.4 ) : ColorChannel * (1.0 / 12.92);
+}
+
+vec3 sRGBToLinear( vec3 Color )
+{
+ return vec3(
+ sRGBToLinearChannel(Color.r),
+ sRGBToLinearChannel(Color.g),
+ sRGBToLinearChannel(Color.b));
+}
+
+void main()
+{
+ TexCoords = InTexCoords;
+
+ Color.rgb = sRGBToLinear(InColor.rgb);
+ Color.a = InColor.a;
+
+ SecondaryColor.rgb = sRGBToLinear(InSecondaryColor.rgb);
+ SecondaryColor.a = InSecondaryColor.a;
+
+ Position = vec4( InPosition, 0, 1 );
+
+ gl_Position = ViewProjectionMatrix * vec4( InPosition, 0, 1 );
+}
diff --git a/Content/Shader/StandaloneRenderer/OpenGL/SlateElementPixelShader.glsl b/Content/Shader/StandaloneRenderer/OpenGL/SlateElementPixelShader.glsl
new file mode 100644
index 0000000..8bae1b2
--- /dev/null
+++ b/Content/Shader/StandaloneRenderer/OpenGL/SlateElementPixelShader.glsl
@@ -0,0 +1,352 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+// handle differences between ES and full GL shaders
+#if PLATFORM_USES_GLES
+precision highp float;
+#else
+// #version 120 at the beginning is added in FSlateOpenGLShader::CompileShader()
+#extension GL_EXT_gpu_shader4 : enable
+#endif
+
+#ifndef USE_709
+#define USE_709 0
+#endif // USE_709
+
+// Shader types
+#define ST_Default 0
+#define ST_Border 1
+#define ST_GrayscaleFont 2
+#define ST_ColorFont 3
+#define ST_Line 4
+#define ST_RoundedBox 7
+
+#define USE_LEGACY_DISABLED_EFFECT 0
+
+/** Display gamma x:gamma curve adjustment, y:inverse gamma (1/GEngine->DisplayGamma) */
+uniform vec2 GammaValues = vec2(1, 1/2.2);
+
+// Draw effects
+uniform bool EffectsDisabled;
+uniform bool IgnoreTextureAlpha;
+
+uniform vec4 ShaderParams;
+uniform vec4 ShaderParams2;
+uniform int ShaderType;
+uniform sampler2D ElementTexture;
+
+#if PLATFORM_MAC
+// GL_TEXTURE_RECTANGLE_ARB support, used by the web surface on macOS
+uniform bool UseTextureRectangle;
+uniform sampler2DRect ElementRectTexture;
+uniform vec2 Size;
+#endif
+
+in vec4 Position;
+in vec4 TexCoords;
+in vec4 Color;
+in vec4 SecondaryColor;
+out vec4 fragColor;
+
+vec3 maxWithScalar(float test, vec3 values)
+{
+ return vec3(max(test, values.x), max(test, values.y), max(test, values.z));
+}
+
+vec3 powScalar(vec3 values, float power)
+{
+ return vec3(pow(values.x, power), pow(values.y, power), pow(values.z, power));
+}
+
+vec3 LinearTo709Branchless(vec3 lin)
+{
+ lin = maxWithScalar(6.10352e-5, lin); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
+ return min(lin * 4.5, powScalar(maxWithScalar(0.018, lin), 0.45) * 1.099 - 0.099);
+}
+
+vec3 LinearToSrgbBranchless(vec3 lin)
+{
+ lin = maxWithScalar(6.10352e-5, lin); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
+ return min(lin * 12.92, powScalar(maxWithScalar(0.00313067, lin), 1.0/2.4) * 1.055 - 0.055);
+ // Possible that mobile GPUs might have native pow() function?
+ //return min(lin * 12.92, exp2(log2(max(lin, 0.00313067)) * (1.0/2.4) + log2(1.055)) - 0.055);
+}
+
+float LinearToSrgbBranchingChannel(float lin)
+{
+ if(lin < 0.00313067) return lin * 12.92;
+ return pow(lin, (1.0/2.4)) * 1.055 - 0.055;
+}
+
+vec3 LinearToSrgbBranching(vec3 lin)
+{
+ return vec3(
+ LinearToSrgbBranchingChannel(lin.r),
+ LinearToSrgbBranchingChannel(lin.g),
+ LinearToSrgbBranchingChannel(lin.b));
+}
+
+float sRGBToLinearChannel( float ColorChannel )
+{
+ return ColorChannel > 0.04045 ? pow( ColorChannel * (1.0 / 1.055) + 0.0521327, 2.4 ) : ColorChannel * (1.0 / 12.92);
+}
+
+vec3 sRGBToLinear( vec3 Color )
+{
+ return vec3(sRGBToLinearChannel(Color.r),
+ sRGBToLinearChannel(Color.g),
+ sRGBToLinearChannel(Color.b));
+}
+
+/**
+ * @param GammaCurveRatio The curve ratio compared to a 2.2 standard gamma, e.g. 2.2 / DisplayGamma. So normally the value is 1.
+ */
+vec3 ApplyGammaCorrection(vec3 LinearColor, float GammaCurveRatio)
+{
+ // Apply "gamma" curve adjustment.
+ vec3 CorrectedColor = powScalar(LinearColor, GammaCurveRatio);
+
+#if PLATFORM_MAC
+ // Note, MacOSX native output is raw gamma 2.2 not sRGB!
+ //CorrectedColor = pow(CorrectedColor, 1.0/2.2);
+ CorrectedColor = LinearToSrgbBranching(CorrectedColor);
+#else
+#if USE_709
+ // Didn't profile yet if the branching version would be faster (different linear segment).
+ CorrectedColor = LinearTo709Branchless(CorrectedColor);
+#else
+ CorrectedColor = LinearToSrgbBranching(CorrectedColor);
+#endif
+
+#endif
+
+ return CorrectedColor;
+}
+
+vec3 GammaCorrect(vec3 InColor)
+{
+ vec3 CorrectedColor = InColor;
+
+ // gamma correct
+ //#if PLATFORM_USES_GLES
+ // OutColor.rgb = sqrt( OutColor.rgb );
+ //#else
+ // OutColor.rgb = pow(OutColor.rgb, vec3(1.0/2.2));
+ //#endif
+
+#if !PLATFORM_USES_GLES
+ if( GammaValues.y != 1.0f )
+ {
+ CorrectedColor = ApplyGammaCorrection(CorrectedColor, GammaValues.x);
+ }
+#endif
+
+ return CorrectedColor;
+}
+
+vec4 GetGrayscaleFontElementColor()
+{
+ vec4 OutColor = Color;
+#if PLATFORM_LINUX
+ OutColor.a *= texture2D(ElementTexture, TexCoords.xy).r; // OpenGL 3.2+ uses Red for single channel textures
+#else
+ OutColor.a *= texture2D(ElementTexture, TexCoords.xy).a;
+#endif
+
+ return OutColor;
+}
+
+vec4 GetColorFontElementColor()
+{
+ vec4 OutColor = Color;
+
+ OutColor *= texture2D(ElementTexture, TexCoords.xy);
+
+ return OutColor;
+}
+
+vec4 GetDefaultElementColor()
+{
+ vec4 OutColor = Color;
+
+ vec4 TextureColor;
+#if PLATFORM_MAC
+ if ( UseTextureRectangle )
+ {
+ TextureColor = texture2DRect(ElementRectTexture, TexCoords.xy*TexCoords.zw*Size).bgra;
+ }
+ else
+#endif
+ {
+ TextureColor = texture2D(ElementTexture, TexCoords.xy*TexCoords.zw);
+ }
+
+ if( IgnoreTextureAlpha )
+ {
+ TextureColor.a = 1.0;
+ }
+ OutColor *= TextureColor;
+ return OutColor;
+}
+
+vec4 GetBorderElementColor()
+{
+ vec4 OutColor = Color;
+ vec4 InTexCoords = TexCoords;
+ vec2 NewUV;
+ if( InTexCoords.z == 0.0 && InTexCoords.w == 0.0 )
+ {
+ NewUV = InTexCoords.xy;
+ }
+ else
+ {
+ vec2 MinUV;
+ vec2 MaxUV;
+
+ if( InTexCoords.z > 0.0 )
+ {
+ MinUV = vec2(ShaderParams.x,0.0);
+ MaxUV = vec2(ShaderParams.y,1.0);
+ InTexCoords.w = 1.0;
+ }
+ else
+ {
+ MinUV = vec2(0.0,ShaderParams.z);
+ MaxUV = vec2(1.0,ShaderParams.w);
+ InTexCoords.z = 1.0;
+ }
+
+ NewUV = InTexCoords.xy*InTexCoords.zw;
+ NewUV = fract(NewUV);
+ NewUV = mix(MinUV,MaxUV,NewUV);
+
+ }
+
+ vec4 TextureColor = texture2D(ElementTexture, NewUV);
+ if( IgnoreTextureAlpha )
+ {
+ TextureColor.a = 1.0;
+ }
+
+ OutColor *= TextureColor;
+ return OutColor;
+}
+
+float GetRoundedBoxDistance(vec2 pos, vec2 center, float radius, float inset)
+{
+ // distance from center
+ pos = abs(pos - center);
+
+ // distance from the inner corner
+ pos = pos - (center - vec2(radius + inset, radius + inset));
+
+ // use distance to nearest edge when not in quadrant with radius
+ // this handles an edge case when radius is very close to thickness
+ // otherwise we're in the quadrant with the radius,
+ // just use the analytic signed distance function
+ return mix( length(pos) - radius,
+ max(pos.x - radius, pos.y - radius),
+ float(pos.x <= 0 || pos.y <=0) );
+}
+
+vec4 GetRoundedBoxElementColor()
+{
+ vec2 size = ShaderParams.zw;
+ vec2 pos = size * TexCoords.xy;
+ vec2 center = size / 2.0;
+
+ //X = Top Left, Y = Top Right, Z = Bottom Right, W = Bottom Left */
+ vec4 cornerRadii = ShaderParams2;
+
+ // figure out which radius to use based on which quadrant we're in
+ vec2 quadrant = step(TexCoords.xy, vec2(.5,.5));
+
+ float left = mix(cornerRadii.y, cornerRadii.x, quadrant.x);
+ float right = mix(cornerRadii.z, cornerRadii.w, quadrant.x);
+ float radius = mix(right, left, quadrant.y);
+
+ float thickness = ShaderParams.y;
+
+ // Compute the distances internal and external to the border outline
+ float dext = GetRoundedBoxDistance(pos, center, radius, 0.0);
+ float din = GetRoundedBoxDistance(pos, center, max(radius - thickness, 0), thickness);
+
+ // Compute the border intensity and fill intensity with a smooth transition
+ float spread = 0.5;
+ float bi = smoothstep(spread, -spread, dext);
+ float fi = smoothstep(spread, -spread, din);
+
+ // alpha blend the external color
+ vec4 fill = GetDefaultElementColor();
+ vec4 border = SecondaryColor;
+ vec4 OutColor = mix(border, fill, float(thickness > radius));
+ OutColor.a = 0.0;
+
+ // blend in the border and fill colors
+ OutColor = mix(OutColor, border, bi);
+ OutColor = mix(OutColor, fill, fi);
+ return OutColor;
+}
+
+vec4 GetLineSegmentElementColor()
+{
+ vec2 Gradient = TexCoords.xy;
+
+ vec2 OutsideFilterUV = vec2(1.0, 1.0);
+ vec2 InsideFilterUV = vec2(ShaderParams.x, 0.0);
+ vec2 LineCoverage = smoothstep(OutsideFilterUV, InsideFilterUV, abs(Gradient));
+
+ vec4 OutColor = Color;
+ OutColor.a *= LineCoverage.x * LineCoverage.y;
+ return OutColor;
+}
+
+void main()
+{
+ vec4 OutColor;
+
+ if( ShaderType == ST_Default )
+ {
+ OutColor = GetDefaultElementColor();
+ }
+ else if( ShaderType == ST_RoundedBox )
+ {
+ OutColor = GetRoundedBoxElementColor();
+ }
+ else if( ShaderType == ST_Border )
+ {
+ OutColor = GetBorderElementColor();
+ }
+ else if( ShaderType == ST_GrayscaleFont )
+ {
+ OutColor = GetGrayscaleFontElementColor();
+ }
+ else if( ShaderType == ST_ColorFont )
+ {
+ OutColor = GetColorFontElementColor();
+ }
+ else
+ {
+ OutColor = GetLineSegmentElementColor();
+ }
+
+ // gamma correct
+ OutColor.rgb = GammaCorrect(OutColor.rgb);
+
+ if( EffectsDisabled )
+ {
+ #if USE_LEGACY_DISABLED_EFFECT
+ //desaturate
+ vec3 LumCoeffs = vec3( 0.3, 0.59, .11 );
+ float Lum = dot( LumCoeffs, OutColor.rgb );
+ OutColor.rgb = mix( OutColor.rgb, vec3(Lum,Lum,Lum), .8 );
+
+ vec3 Grayish = vec3(0.4, 0.4, 0.4);
+
+ OutColor.rgb = mix( OutColor.rgb, Grayish, clamp( distance( OutColor.rgb, Grayish ), 0.0, 0.8) );
+ #else
+ OutColor.a *= .45f;
+ #endif
+ }
+
+ fragColor = OutColor.bgra;
+}
diff --git a/Content/Shader/StandaloneRenderer/OpenGL/SplashFragmentShader.glsl b/Content/Shader/StandaloneRenderer/OpenGL/SplashFragmentShader.glsl
new file mode 100644
index 0000000..cc0889e
--- /dev/null
+++ b/Content/Shader/StandaloneRenderer/OpenGL/SplashFragmentShader.glsl
@@ -0,0 +1,20 @@
+
+#if PLATFORM_USES_GLES
+precision highp float;
+#else
+// #version 120 at the beginning is added in FSlateOpenGLShader::CompileShader()
+#extension GL_EXT_gpu_shader4 : enable
+#endif
+
+varying vec2 textureCoordinate;
+
+uniform sampler2D SplashTexture;
+
+void main()
+{
+ // OpenGL has 0,0 the "math" way
+ vec2 tc = vec2(textureCoordinate.s, 1.0-textureCoordinate.t);
+
+ gl_FragColor = texture2D(SplashTexture, tc);
+
+}
diff --git a/Content/Shader/StandaloneRenderer/OpenGL/SplashVertexShader.glsl b/Content/Shader/StandaloneRenderer/OpenGL/SplashVertexShader.glsl
new file mode 100644
index 0000000..8b296ff
--- /dev/null
+++ b/Content/Shader/StandaloneRenderer/OpenGL/SplashVertexShader.glsl
@@ -0,0 +1,12 @@
+attribute vec2 InPosition;
+
+varying vec2 textureCoordinate;
+
+void main()
+{
+ // We do not need texture coordinates. We calculate using position.
+ textureCoordinate = InPosition * 0.5 + 0.5;
+
+ gl_Position = vec4(InPosition, 0.0, 1.0);
+
+}
\ No newline at end of file
diff --git a/Content/Skin/Default/BlackBrush.png b/Content/Skin/Default/BlackBrush.png
new file mode 100644
index 0000000..6f8dcb6
Binary files /dev/null and b/Content/Skin/Default/BlackBrush.png differ
diff --git a/Content/Skin/Default/CloseButton_Normal.png b/Content/Skin/Default/CloseButton_Normal.png
new file mode 100644
index 0000000..e60a6e3
Binary files /dev/null and b/Content/Skin/Default/CloseButton_Normal.png differ
diff --git a/Content/Skin/Default/PianoRollBackground.png b/Content/Skin/Default/PianoRollBackground.png
new file mode 100644
index 0000000..99d42d3
Binary files /dev/null and b/Content/Skin/Default/PianoRollBackground.png differ
diff --git a/Content/Skin/Default/Roboto-Light.ttf b/Content/Skin/Default/Roboto-Light.ttf
new file mode 100644
index 0000000..219063a
Binary files /dev/null and b/Content/Skin/Default/Roboto-Light.ttf differ
diff --git a/Content/Skin/Default/Skin.ini b/Content/Skin/Default/Skin.ini
new file mode 100644
index 0000000..3b5023e
--- /dev/null
+++ b/Content/Skin/Default/Skin.ini
@@ -0,0 +1,19 @@
+[Resource]
+WhiteBrush="WhiteBrush"
+
+VolumeMeter="VolumeMeter"
+VolumeMeterSpace=1
+
+DefaultFont="Roboto-Light"
+DefaultFontSize=12
+
+PianoRollBackground="PianoRollBackground"
+PianoRollBackgroundSize="X=3840, Y=2160"
+
+CloseButtonSize="X=16, Y=16"
+CloseButtonNormal="CloseButton_Normal"
+CloseButtonHover="CloseButton_Hover"
+CloseButtonPress="CloseButton_Press"
+
+WhiteKey="WhiteBrush"
+BlackKey="BlackBrush"
diff --git a/Content/Skin/Default/VolumeMeter.png b/Content/Skin/Default/VolumeMeter.png
new file mode 100644
index 0000000..0512a3e
Binary files /dev/null and b/Content/Skin/Default/VolumeMeter.png differ
diff --git a/Content/Skin/Default/WhiteBrush.png b/Content/Skin/Default/WhiteBrush.png
new file mode 100644
index 0000000..dc2dbeb
Binary files /dev/null and b/Content/Skin/Default/WhiteBrush.png differ
diff --git a/Content/Skin/Default/{9F6605E9-2440-C398-95A5-D5F1BC998087}.jpg b/Content/Skin/Default/{9F6605E9-2440-C398-95A5-D5F1BC998087}.jpg
new file mode 100644
index 0000000..5fcec9a
Binary files /dev/null and b/Content/Skin/Default/{9F6605E9-2440-C398-95A5-D5F1BC998087}.jpg differ
diff --git a/Source/Arona.Target.cs b/Source/Arona.Target.cs
new file mode 100644
index 0000000..6a05d43
--- /dev/null
+++ b/Source/Arona.Target.cs
@@ -0,0 +1,24 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+using UnrealBuildTool;
+using System.Collections.Generic;
+
+[SupportedPlatforms(UnrealPlatformClass.Desktop)]
+[SupportedPlatforms("IOS")]
+public class AronaTarget : TargetRules
+{
+ public AronaTarget(TargetInfo Target) : base(Target)
+ {
+ Type = TargetType.Program;
+ LinkType = TargetLinkType.Default;
+ LaunchModuleName = "Arona";
+
+ // Arona.exe has no exports, so no need to verify that a .lib and .exp file was emitted by
+ // the linker.
+ bHasExports = false;
+
+ // Make sure to get all code in SlateEditorStyle compiled in
+ bBuildDeveloperTools = false;
+ bUsesSlate = true;
+ }
+}
diff --git a/Source/Arona/Arona.Build.cs b/Source/Arona/Arona.Build.cs
new file mode 100644
index 0000000..1276a68
--- /dev/null
+++ b/Source/Arona/Arona.Build.cs
@@ -0,0 +1,55 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+using System.IO;
+using UnrealBuildTool;
+
+public class Arona : ModuleRules
+{
+ public Arona(ReadOnlyTargetRules Target) : base(Target)
+ {
+ PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
+ PublicIncludePaths.Add(Path.Combine(EngineDirectory, "Source", "Runtime/Launch/Public"));
+
+ PrivateDependencyModuleNames.AddRange(
+ new string[] {
+ "AppFramework",
+ "Core",
+ "ApplicationCore",
+ "Projects",
+ "Slate",
+ "SlateCore",
+ "StandaloneRenderer",
+ "DesktopPlatform",
+ "AronaCore",
+ "SignalProcessing"
+ }
+ );
+
+ PrivateIncludePathModuleNames.AddRange(
+ new string[] {
+ "StandaloneRenderer"
+ }
+ );
+
+ PrivateIncludePaths.Add(Path.Combine(EngineDirectory, "Source", "Runtime/Launch/Private")); // For LaunchEngineLoop.cpp include
+
+ if (Target.Platform == UnrealTargetPlatform.IOS || Target.Platform == UnrealTargetPlatform.TVOS)
+ {
+ PrivateDependencyModuleNames.AddRange(
+ new string [] {
+ "NetworkFile",
+ "StreamingFile"
+ }
+ );
+ }
+
+ if (Target.IsInPlatformGroup(UnrealPlatformGroup.Linux))
+ {
+ PrivateDependencyModuleNames.AddRange(
+ new string[] {
+ "UnixCommonStartup"
+ }
+ );
+ }
+ }
+}
diff --git a/Source/Arona/EntryPoints/AronaApp.cpp b/Source/Arona/EntryPoints/AronaApp.cpp
new file mode 100644
index 0000000..d7a13bb
--- /dev/null
+++ b/Source/Arona/EntryPoints/AronaApp.cpp
@@ -0,0 +1,108 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "AronaApp.h"
+
+#include "App.h"
+#include "AronaMain.h"
+#include "ConfigCacheIni.h"
+#include "OutputDeviceRedirector.h"
+#include "QueuedThreadPool.h"
+#include "QueuedThreadPoolWrapper.h"
+#include "Framework/Application/SlateApplication.h"
+#include "Framework/Docking/TabManager.h"
+#include "Framework/Docking/WorkspaceItem.h"
+#include "StandaloneRenderer.h"
+#include "StdOutputDevice.h"
+#include "Singleton/SingletonManager.h"
+#include "Stats2.h"
+#include "Test.h"
+#include "Singleton/CallRateLimiterManager.h"
+#include "Thread/MainThreadEventList.h"
+#include "UI/Widget/WindowManager.h"
+
+IMPLEMENT_APPLICATION(Arona, "Arona");
+
+#define LOCTEXT_NAMESPACE "Arona"
+
+int32 Init(const TCHAR* CmdLine)
+{
+ FCommandLine::Set(CmdLine);
+ FGenericPlatformProcess::SetShaderDir(*FPaths::Combine(FPaths::ProjectContentDir(), TEXT("Shader")));
+ GThreadPool = new FQueuedLowLevelThreadPool();
+ InitLog();
+ // BUG: Memoty leak
+// #if STATS
+// FThreadStats::StartThread();
+// #endif
+ FPlatformMisc::PlatformPreInit();
+ FConfigCacheIni::InitializeConfigSystem();
+ FPlatformMisc::PlatformInit();
+ FPlatformMisc::SetGracefulTerminationHandler();
+
+ {
+ FTaskTagScope Scope(ETaskTag::EGameThread);
+ FTaskGraphInterface::Startup(FPlatformMisc::NumberOfWorkerThreadsToSpawn());
+ FTaskGraphInterface::Get().AttachToThread(ENamedThreads::GameThread);
+
+ FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::TaskGraphSystemReady);
+ }
+ return 0;
+}
+
+
+int RunArona( const TCHAR* CommandLine )
+{
+ Init(CommandLine);
+
+ // crank up a normal Slate application using the platform's standalone renderer
+ FSlateApplication::InitializeAsStandaloneApplication(GetStandardStandaloneRenderer());
+ FSlateApplication::InitHighDPI(true);
+
+ FSingletonManager::GetInstance().Init();
+
+ FMainThreadEventList& MainThreadEventList = FMainThreadEventList::Get();
+ FWindowManager& WindowManager = FWindowManager::Get();
+ FCallRateLimiterManager& RateLimiterManager = FCallRateLimiterManager::Get();
+
+ // AronaTest();
+
+ constexpr float FrameRate = 1.f / 360.0f;
+ FSlateApplication& SlateApplication = FSlateApplication::Get();
+ FTaskGraphInterface& TaskGraphInterface = FTaskGraphInterface::Get();
+ FTSTicker& CoreTicker = FTSTicker::GetCoreTicker();
+
+ // loop while the server does the rest
+ while (!IsEngineExitRequested())
+ {
+ BeginExitIfRequested();
+
+ TaskGraphInterface.ProcessThreadUntilIdle(ENamedThreads::GameThread);
+ CoreTicker.Tick(FApp::GetDeltaTime());
+ SlateApplication.PumpMessages();
+ MainThreadEventList.ProcessMessage();
+
+ SlateApplication.Tick();
+ FPlatformProcess::SleepNoStats(FrameRate);
+ RateLimiterManager.Update(FApp::GetDeltaTime());
+
+ GFrameCounter++;
+ }
+
+
+
+ FSingletonManager::GetInstance().Release();
+ FCoreDelegates::OnExit.Broadcast();
+ FSlateApplication::Shutdown();
+ FModuleManager::Get().UnloadModulesAtShutdown();
+ FTaskGraphInterface::Shutdown();
+ FPlatformMisc::PlatformTearDown();
+ delete GThreadPool;
+ // BUG: Memoty leak
+// #if STATS
+// FThreadStats::StopThread();
+// #endif
+ TearDownLog();
+ return 0;
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/Source/Arona/EntryPoints/AronaApp.h b/Source/Arona/EntryPoints/AronaApp.h
new file mode 100644
index 0000000..4296c8c
--- /dev/null
+++ b/Source/Arona/EntryPoints/AronaApp.h
@@ -0,0 +1,10 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+
+/**
+ * Run the Arona .
+ */
+int RunArona(const TCHAR* Commandline);
diff --git a/Source/Arona/EntryPoints/AronaMain.cpp b/Source/Arona/EntryPoints/AronaMain.cpp
new file mode 100644
index 0000000..22e2464
--- /dev/null
+++ b/Source/Arona/EntryPoints/AronaMain.cpp
@@ -0,0 +1,32 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "AronaMain.h"
+#include "UI/Style/AronaStyle.h"
+#include "UI/AronaModuleCommands.h"
+
+#include "Widgets/Docking/SDockTab.h"
+#include "Widgets/Layout/SBox.h"
+#include "Widgets/Text/STextBlock.h"
+
+
+#define LOCTEXT_NAMESPACE "FAronaModule"
+
+void FAronaMain::StartupModule()
+{
+ FAronaModuleCommands::Register();
+
+ AppCommands = MakeShareable(new FUICommandList);
+}
+
+void FAronaMain::ShutdownModule()
+{
+ // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
+ // we call this function before unloading the module.
+ FAronaModuleCommands::Unregister();
+
+ FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(AronaModuleTabName);
+}
+
+#undef LOCTEXT_NAMESPACE
+
+IMPLEMENT_MODULE(FAronaMain, AronaMain)
diff --git a/Source/Arona/EntryPoints/AronaMain.h b/Source/Arona/EntryPoints/AronaMain.h
new file mode 100644
index 0000000..ab14f7b
--- /dev/null
+++ b/Source/Arona/EntryPoints/AronaMain.h
@@ -0,0 +1,23 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Modules/ModuleManager.h"
+
+class FToolBarBuilder;
+class FMenuBuilder;
+static const FName AronaModuleTabName("AronaModule");
+
+class FAronaMain : public IModuleInterface
+{
+public:
+
+ /** IModuleInterface implementation */
+ virtual void StartupModule() override;
+ virtual void ShutdownModule() override;
+private:
+
+private:
+ TSharedPtr AppCommands;
+};
diff --git a/Source/Arona/EntryPoints/IOS/IOSAronaMain.cpp b/Source/Arona/EntryPoints/IOS/IOSAronaMain.cpp
new file mode 100644
index 0000000..65bab4e
--- /dev/null
+++ b/Source/Arona/EntryPoints/IOS/IOSAronaMain.cpp
@@ -0,0 +1,111 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "AronaApp.h"
+#include "IOS/IOSAppDelegate.h"
+#include "IOS/IOSCommandLineHelper.h"
+#include "IOS/SlateOpenGLESView.h"
+#include "Widgets/Testing/STestSuite.h"
+
+#import
+
+
+#define IOS_MAX_PATH 1024
+#define CMD_LINE_MAX 16384
+
+FString GSavedCommandLine;
+
+void FAppEntry::Suspend()
+{
+}
+
+void FAppEntry::Resume()
+{
+}
+
+void FAppEntry::SuspendTick()
+{
+}
+
+bool FAppEntry::IsStartupMoviePlaying()
+{
+ return false;
+}
+
+
+void FAppEntry::PreInit(IOSAppDelegate* AppDelegate, UIApplication* Application)
+{
+ // make a controller object
+ AppDelegate.SlateController = [[SlateOpenGLESViewController alloc] init];
+
+ // property owns it now
+ [AppDelegate.SlateController release];
+
+ // point to the GL view we want to use
+ AppDelegate.RootView = [AppDelegate.SlateController view];
+
+ [AppDelegate.Window setRootViewController:AppDelegate.SlateController];
+}
+
+
+void FAppEntry::PlatformInit()
+{
+}
+
+
+void FAppEntry::Init()
+{
+ // start up the main loop
+ GEngineLoop.PreInit(FCommandLine::Get());
+
+ // move it to this thread
+ SlateOpenGLESView* View = (SlateOpenGLESView*)[IOSAppDelegate GetDelegate].RootView;
+ [EAGLContext setCurrentContext:View.Context];
+
+ // crank up a normal Slate application using the platform's standalone renderer
+ FSlateApplication::InitializeAsStandaloneApplication(GetStandardStandaloneRenderer());
+
+ // Bring up the test suite.
+ {
+ RestoreSlateTestSuite();
+ }
+
+#if WITH_SHARED_POINTER_TESTS
+ SharedPointerTesting::TestSharedPointer< ESPMode::Fast >();
+ SharedPointerTesting::TestSharedPointer< ESPMode::ThreadSafe >();
+#endif
+
+ // loop while the server does the rest
+ double LastTime = FPlatformTime::Seconds();
+}
+
+
+void FAppEntry::Tick()
+{
+ FSlateApplication::Get().PumpMessages();
+ FSlateApplication::Get().Tick();
+
+ // Sleep
+ FPlatformProcess::Sleep( 0 );
+}
+
+
+void FAppEntry::Shutdown()
+{
+ FSlateApplication::Shutdown();
+}
+
+
+int main(int argc, char *argv[])
+{
+ for (int32 Option = 1; Option < argc; Option++)
+ {
+ GSavedCommandLine += TEXT(" ");
+ GSavedCommandLine += ANSI_TO_TCHAR(argv[Option]);
+ }
+
+ FIOSCommandLineHelper::InitCommandArgs(FString());
+
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([IOSAppDelegate class]));
+ }
+}
diff --git a/Source/Arona/EntryPoints/Linux/AronaMainLinux.cpp b/Source/Arona/EntryPoints/Linux/AronaMainLinux.cpp
new file mode 100644
index 0000000..2ae5f29
--- /dev/null
+++ b/Source/Arona/EntryPoints/Linux/AronaMainLinux.cpp
@@ -0,0 +1,9 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "AronaApp.h"
+#include "UnixCommonStartup.h"
+
+int main(int argc, char *argv[])
+{
+ return CommonUnixMain(argc, argv, &RunArona);
+}
diff --git a/Source/Arona/EntryPoints/Mac/AronaMainMac.cpp b/Source/Arona/EntryPoints/Mac/AronaMainMac.cpp
new file mode 100644
index 0000000..2f44e14
--- /dev/null
+++ b/Source/Arona/EntryPoints/Mac/AronaMainMac.cpp
@@ -0,0 +1,85 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "AronaApp.h"
+#include "HAL/ExceptionHandling.h"
+#include "Mac/CocoaThread.h"
+
+static FString GSavedCommandLine;
+
+@interface UE4AppDelegate : NSObject
+{
+}
+
+@end
+
+@implementation UE4AppDelegate
+
+//handler for the quit apple event used by the Dock menu
+- (void)handleQuitEvent:(NSAppleEventDescriptor*)Event withReplyEvent:(NSAppleEventDescriptor*)ReplyEvent
+{
+ [NSApp terminate:self];
+}
+
+- (void) runGameThread:(id)Arg
+{
+ FPlatformMisc::SetGracefulTerminationHandler();
+ FPlatformMisc::SetCrashHandler(nullptr);
+
+ RunArona(*GSavedCommandLine);
+
+ [NSApp terminate: self];
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)Sender;
+{
+ if(!IsEngineExitRequested() || ([NSThread gameThread] && [NSThread gameThread] != [NSThread mainThread]))
+ {
+ RequestEngineExit(TEXT("applicationShouldTerminate"));
+ return NSTerminateLater;
+ }
+ else
+ {
+ return NSTerminateNow;
+ }
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)Notification
+{
+ //install the custom quit event handler
+ NSAppleEventManager* appleEventManager = [NSAppleEventManager sharedAppleEventManager];
+ [appleEventManager setEventHandler:self andSelector:@selector(handleQuitEvent:withReplyEvent:) forEventClass:kCoreEventClass andEventID:kAEQuitApplication];
+
+ RunGameThread(self, @selector(runGameThread:));
+}
+
+@end
+
+int main(int argc, char *argv[])
+{
+ for (int32 Option = 1; Option < argc; Option++)
+ {
+ GSavedCommandLine += TEXT(" ");
+ FString Argument(ANSI_TO_TCHAR(argv[Option]));
+ if (Argument.Contains(TEXT(" ")))
+ {
+ if (Argument.Contains(TEXT("=")))
+ {
+ FString ArgName;
+ FString ArgValue;
+ Argument.Split( TEXT("="), &ArgName, &ArgValue );
+ Argument = FString::Printf( TEXT("%s=\"%s\""), *ArgName, *ArgValue );
+ }
+ else
+ {
+ Argument = FString::Printf(TEXT("\"%s\""), *Argument);
+ }
+ }
+ GSavedCommandLine += Argument;
+ }
+
+ SCOPED_AUTORELEASE_POOL;
+ [NSApplication sharedApplication];
+ [NSApp setDelegate:[UE4AppDelegate new]];
+ [NSApp run];
+ return 0;
+}
diff --git a/Source/Arona/EntryPoints/Windows/AronaMainWindows.cpp b/Source/Arona/EntryPoints/Windows/AronaMainWindows.cpp
new file mode 100644
index 0000000..9e1ab35
--- /dev/null
+++ b/Source/Arona/EntryPoints/Windows/AronaMainWindows.cpp
@@ -0,0 +1,17 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+
+#include "EntryPoints/AronaApp.h"
+#include "Windows/WindowsHWrapper.h"
+
+
+/**
+ * WinMain, called when the application is started
+ */
+int WINAPI WinMain( _In_ HINSTANCE hInInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR, _In_ int nCmdShow )
+{
+ // do the Arona thing
+ RunArona(GetCommandLineW());
+
+ return 0;
+}
diff --git a/Source/Arona/Render/UpdatableTexture.cpp b/Source/Arona/Render/UpdatableTexture.cpp
new file mode 100644
index 0000000..93f1778
--- /dev/null
+++ b/Source/Arona/Render/UpdatableTexture.cpp
@@ -0,0 +1,65 @@
+#include "UpdatableTexture.h"
+
+#include "Async.h"
+#include "Thread/MainThreadEventList.h"
+#include "SlateApplication.h"
+
+DECLARE_THREAD_MESSAGE(FMainThreadEventList, UpdatableTexture,
+FUpdatableTexture* Texture;
+)
+{
+ Args.Texture->Update();
+ Args.Texture->UpdateCaller.Reset();
+ UE_LOG(LogTemp, Log, TEXT("2"))
+}
+
+FUpdatableTexture::FUpdatableTexture(FIntPoint InTextureSize) : UpdateCaller(&FUpdatableTexture::AsyncUpdate, this)
+{
+ Data.Resize(InTextureSize);
+ Texture = FSlateApplication::Get().GetRenderer()->CreateUpdatableTexture(Data.TextureSize.X, Data.TextureSize.Y);
+ Texture->UpdateTexture(Data.Data);
+}
+
+void FUpdatableTexture::Resize(FIntPoint NewSize)
+{
+ if (NewSize.X > 16384)
+ NewSize.X = 16384;
+ if (NewSize.Y > 16384)
+ NewSize.Y = 16384;
+
+ NextSize = NewSize;
+ ReSized = true;
+}
+
+void FUpdatableTexture::RequestUpdate(bool Async)
+{
+ UE_LOG(LogTemp, Log, TEXT("Request Update"))
+ if (Async)
+ {
+ UpdateCaller.Call();
+ }
+ else
+ {
+ RedrawImage.ExecuteIfBound(Data);
+ Update();
+ }
+}
+
+void FUpdatableTexture::Update()
+{
+ if (ReSized)
+ Texture->ResizeTexture(Data.TextureSize.X, Data.TextureSize.Y);
+ Texture->UpdateTexture(Data.Data);
+ ReSized = false;
+ OnOverRedraw.ExecuteIfBound();
+}
+
+void FUpdatableTexture::AsyncUpdate()
+{
+ Async(EAsyncExecution::ThreadPool, [this]()
+ {
+ Data.Resize(NextSize);
+ RedrawImage.ExecuteIfBound(Data);
+ PUSH_THREAD_EVENT(UpdatableTexture, this);
+ });
+}
diff --git a/Source/Arona/Render/UpdatableTexture.h b/Source/Arona/Render/UpdatableTexture.h
new file mode 100644
index 0000000..4bac32d
--- /dev/null
+++ b/Source/Arona/Render/UpdatableTexture.h
@@ -0,0 +1,124 @@
+#pragma once
+#include "CoreMinimal.h"
+#include "RenderingCommon.h"
+#include "SlateUpdatableTexture.h"
+#include "Thread/ThreadMessage.h"
+#include "Misc/CallRateLimiter.h"
+
+struct FImageData
+{
+ TArray Data;
+ FIntPoint TextureSize = FIntPoint::ZeroValue;
+
+ bool Resize(FIntPoint NewSize)
+ {
+ if (NewSize == TextureSize)
+ return false;
+ if (NewSize.X <= 0 || NewSize.Y <= 0)
+ return false;
+ TextureSize = NewSize;
+ Data.SetNumZeroed(TextureSize.X * TextureSize.Y * 4);
+ return true;
+ }
+
+ void ClearColor(const FColor& Color)
+ {
+ for (int32 x = 0; x < TextureSize.X; ++x)
+ {
+ for (int32 y = 0; y < TextureSize.Y; ++y)
+ {
+ DrawPixel(x, y, Color);
+ }
+ }
+ }
+
+ void DrawPixel(const FIntPoint& Pos, const FColor& Color)
+ {
+ DrawPixel(Pos.X, Pos.Y, Color);
+ }
+
+ void DrawPixel(int32 X, int32 Y, const FColor& Color)
+ {
+ #if UE_BUILD_DEBUG
+ const bool Error = X < 0 || X >= TextureSize.X || Y < 0 || Y >= TextureSize.Y;
+ ensureMsgf(!Error, TEXT("X: %d, Y: %d, TextureSize: %d, %d"), X, Y, TextureSize.X, TextureSize.Y);
+ if (Error)
+ return;
+ #endif
+ const int32 Pixel = X + Y * TextureSize.X;
+ uint8* Ptr = Data.GetData() + Pixel * 4;
+ *Ptr++ = Color.R;
+ *Ptr++ = Color.G;
+ *Ptr++ = Color.B;
+ *Ptr = Color.A;
+ }
+
+ void DrawLine(const FIntPoint& P1, const FIntPoint& P2, const FColor& Color)
+ {
+ int32 x1 = P1.X;
+ int32 y1 = P1.Y;
+ const int32& x2 = P2.X;
+ const int32& y2 = P2.Y;
+
+ const int dx = abs(x2 - x1);
+ const int dy = abs(y2 - y1);
+ const int sx = (x1 < x2) ? 1 : -1;
+ const int sy = (y1 < y2) ? 1 : -1;
+ int err = dx - dy;
+
+ while (true)
+ {
+ DrawPixel(x1, y1, Color);
+
+ if (x1 == x2 && y1 == y2)
+ break;
+
+ int e2 = 2 * err;
+ if (e2 > -dy)
+ {
+ err -= dy;
+ x1 += sx;
+ }
+ if (e2 < dx)
+ {
+ err += dx;
+ y1 += sy;
+ }
+ }
+ }
+
+ FColor& operator[](int32 PixelIndex)
+ {
+ return *(FColor*)(Data.GetData() + PixelIndex * 4);
+ }
+};
+
+DECLARE_DELEGATE_OneParam(FUpdatableImageDataEvent, FImageData&)
+
+class FUpdatableTexture : public ISlateViewport, public TSharedFromThis
+{
+ FRIEND_THREAD_MESSAGE(UpdatableTexture)
+public:
+ FUpdatableTexture(FIntPoint InTextureSize);
+
+ void Resize(FIntPoint NewSize);
+ void RequestUpdate(bool Async = true);
+
+ virtual FIntPoint GetSize() const override { return Data.TextureSize; }
+ virtual FSlateShaderResource* GetViewportRenderTargetTexture() const override { return Texture->GetSlateResource(); }
+ virtual bool RequiresVsync() const override { return false; }
+ ISlateViewport* GetViewportInterface() { return this; }
+
+ FUpdatableImageDataEvent RedrawImage;
+ FSimpleDelegate OnOverRedraw;
+private:
+ FCallOnce UpdateCaller;
+
+ void Update(); // 只能在主线程调用
+ void AsyncUpdate();
+
+ FSlateUpdatableTexture* Texture;
+ FImageData Data;
+ bool ReSized = false;
+ FIntPoint NextSize;
+};
diff --git a/Source/Arona/Singleton/SingletonManager.cpp b/Source/Arona/Singleton/SingletonManager.cpp
new file mode 100644
index 0000000..1067bc8
--- /dev/null
+++ b/Source/Arona/Singleton/SingletonManager.cpp
@@ -0,0 +1,53 @@
+#include "SingletonManager.h"
+
+#include "Misc/AronaConfig.h"
+#include "Singleton/CallRateLimiterManager.h"
+#include "Singleton/MidiSequencer.h"
+#include "Singleton/MixerList.h"
+#include "Singleton/PluginHostList.h"
+#include "Singleton/PortAudioAPI.h"
+#include "UI/Widget/WindowManager.h"
+
+#define REGISTER_MANAGER(ManagerClass) RegisterManager(&ManagerClass::Get());
+
+void FSingletonManager::Init()
+{
+ REGISTER_MANAGER(FCallRateLimiterManager)
+ REGISTER_MANAGER(FAronaConfig)
+ REGISTER_MANAGER(FMixerList)
+ REGISTER_MANAGER(FPortAudioAPI)
+ REGISTER_MANAGER(FPluginHostList)
+ REGISTER_MANAGER(FMidiSequencer)
+ REGISTER_MANAGER(FWindowManager)
+
+ for (ISingleton* Manager : Managers)
+ {
+ Manager->PostInit();
+ }
+}
+
+void FSingletonManager::Release()
+{
+ for (int32 i = Managers.Num() - 1; i >= 0; --i)
+ {
+ ISingleton* SingletonImpl = Managers[i];
+ SingletonImpl->BeginRelease();
+ }
+ for (int32 i = Managers.Num() - 1; i >= 0; --i)
+ {
+ ISingleton* SingletonImpl = Managers[i];
+ SingletonImpl->Release();
+ }
+ Managers.Reset();
+}
+
+void FSingletonManager::RegisterManager(ISingleton* Manager)
+{
+ Manager->Init();
+ Managers.Add(Manager);
+ UE_LOG(SingletonLog, Log, TEXT("%s Registered"), *Manager->GetName().ToString());
+}
+
+FSingletonManager::FSingletonManager()
+{
+}
diff --git a/Source/Arona/Singleton/SingletonManager.h b/Source/Arona/Singleton/SingletonManager.h
new file mode 100644
index 0000000..979bd76
--- /dev/null
+++ b/Source/Arona/Singleton/SingletonManager.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "CoreMinimal.h"
+#include "Singleton/Singleton.h"
+
+class FSingletonManager
+{
+public:
+ static FSingletonManager& GetInstance()
+ {
+ static FSingletonManager Instance;
+ return Instance;
+ }
+ static const char* GetName() { return "singleton_manager"; }
+ void Init();
+ void Release();
+
+ void RegisterManager(ISingleton* Manager);
+private:
+ FSingletonManager();
+ TArray Managers;
+};
diff --git a/Source/Arona/Test.cpp b/Source/Arona/Test.cpp
new file mode 100644
index 0000000..964ea2d
--- /dev/null
+++ b/Source/Arona/Test.cpp
@@ -0,0 +1,48 @@
+#include "Test.h"
+
+#include "Midi/MifiFile.h"
+#include "Singleton/MidiSequencer.h"
+#include "Singleton/PluginHostList.h"
+#include "Singleton/PortAudioAPI.h"
+
+void AronaTest()
+{
+ TArray AudioDeviceInfos = FPortAudioAPI::Get().GetDevices();
+ for (const FAudioDeviceInfo& AudioDeviceInfo : AudioDeviceInfos)
+ {
+ UE_LOG(LogTemp, Log, TEXT("Audio Device%d: %s"), AudioDeviceInfo.DeviceIndex, *AudioDeviceInfo.Name);
+ }
+
+ const FString& MidiFilePath = TEXT("E:\\Projects\\Arona\\脑浆炸裂女孩 - 初音ミク.mid");
+ // const FString& PluginFilePath = TEXT("D:\\Projects\\Rolling\\4Front Piano x64.dll");
+ const FString& PluginFilePath = TEXT("F:\\VST\\VST64\\4Front Piano x64.dll");
+
+ FMidiFile Midi;
+ Midi.readFrom(MidiFilePath);
+
+ FMidiSequencer& MidiSequencer = FMidiSequencer::Get();
+ // MidiSequencer.SetTicksPerQuarter(Midi.getTimeFormat());
+
+ FMidiPattern* MidiPattern = MidiSequencer.NewMidiPattern();
+ MidiPattern->Name = TEXT("脑浆炸裂女孩 - 初音ミク");
+
+ for (int i = 0; i < Midi.getNumTracks(); ++i)
+ {
+ FPluginHost* Plugin = FPluginHostList::Get().TryLoadPlugin(PluginFilePath);
+ FPluginHostList::Get().RegisterInstrument(Plugin);
+
+ const FMidiMessageSequence* Track = Midi.getTrack(i);
+ FMidiMessageSequence& Sequence = MidiPattern->GetSequence(Plugin);
+ Sequence.addSequence(*Track, 0);
+ Sequence.updateMatchedPairs();
+ }
+ // FPluginHost* Kontakt = FPluginHostList::Get().TryLoadPlugin(TEXT("I:\\VST\\VST64\\Kontakt.dll"));
+ // FPluginHostList::Get().RegisterInstrument(Kontakt);
+
+
+ // MidiPattern->RequestCreateInstance(0, 0, 0, 0, MidiPattern->GetMidiLength(), 0, MidiPattern->GetSampleLength());
+ // MidiSequencer.PatternSelector.SelectPattern(MidiPattern);
+ // MidiSequencer.Playing = true;
+ FPluginHostList::Get().TryLoadSampler(TEXT("F:\\FL垃圾桶\\Kawaii Anokoga Kiniiranai.mp3"));
+ FPluginHostList::Get().TryLoadSampler(TEXT("F:\\Sample\\Cymatics - Empire Hip Hop Sample Pack\\Melody Loops\\Cymatics - Empire Melody Loop 1 - 100 BPM G Min.wav"));
+}
diff --git a/Source/Arona/Test.h b/Source/Arona/Test.h
new file mode 100644
index 0000000..79b2c07
--- /dev/null
+++ b/Source/Arona/Test.h
@@ -0,0 +1,4 @@
+#pragma once
+#include "CoreMinimal.h"
+
+void AronaTest();
\ No newline at end of file
diff --git a/Source/Arona/UI/AronaModuleCommands.cpp b/Source/Arona/UI/AronaModuleCommands.cpp
new file mode 100644
index 0000000..e1f31c2
--- /dev/null
+++ b/Source/Arona/UI/AronaModuleCommands.cpp
@@ -0,0 +1,11 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "AronaModuleCommands.h"
+
+#define LOCTEXT_NAMESPACE "FAronaModuleModule"
+
+void FAronaModuleCommands::RegisterCommands()
+{
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/Source/Arona/UI/AronaModuleCommands.h b/Source/Arona/UI/AronaModuleCommands.h
new file mode 100644
index 0000000..a16999d
--- /dev/null
+++ b/Source/Arona/UI/AronaModuleCommands.h
@@ -0,0 +1,20 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Framework/Commands/Commands.h"
+#include "UI/Style/AronaStyle.h"
+
+class ARONA_API FAronaModuleCommands : public TCommands
+{
+public:
+
+ FAronaModuleCommands()
+ : TCommands(TEXT("AronaModule"), NSLOCTEXT("Contexts", "AronaModule", "AronaModule application"), NAME_None, FAronaStyle::Get().GetStyleSetName())
+ {
+ }
+
+ // TCommands<> interface
+ virtual void RegisterCommands() override;
+};
\ No newline at end of file
diff --git a/Source/Arona/UI/Style/AronaStyle.cpp b/Source/Arona/UI/Style/AronaStyle.cpp
new file mode 100644
index 0000000..47a2f7d
--- /dev/null
+++ b/Source/Arona/UI/Style/AronaStyle.cpp
@@ -0,0 +1,153 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "AronaStyle.h"
+
+#include "Styling/SlateStyleRegistry.h"
+#include "Framework/Application/SlateApplication.h"
+#include "Misc/AronaConfig.h"
+
+TSharedPtr< FAronaStyle > FAronaStyle::StyleInstance = NULL;
+
+void FAronaStyle::Initialize()
+{
+ if (!StyleInstance.IsValid())
+ {
+ StyleInstance = Create();
+ StyleInstance->LoadConfig();
+ FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance);
+ }
+}
+
+void FAronaStyle::Shutdown()
+{
+ FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance);
+ ensure(StyleInstance.IsUnique());
+ StyleInstance.Reset();
+}
+
+const FButtonStyle* FAronaStyle::GetButtonStyle(const FName& PropertyName, const ANSICHAR* Specifier)
+{
+ return &StyleInstance->GetWidgetStyle(PropertyName, Specifier, nullptr);
+}
+
+const FSlateBrush* FAronaStyle::GetSlateBrush(const FName& PropertyName, const ANSICHAR* Specifier)
+{
+ return StyleInstance->GetBrush(PropertyName, Specifier, nullptr);
+}
+
+FSlateFontInfo FAronaStyle::GetFontInfo(const FName& PropertyName, const ANSICHAR* Specifier)
+{
+ return StyleInstance->GetFontStyle(PropertyName, Specifier);
+}
+
+#define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define BORDER_BRUSH( RelativePath, ... ) FSlateBorderBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define TTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".ttf") ), __VA_ARGS__ )
+#define OTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".otf") ), __VA_ARGS__ )
+
+#define MakeImageBrush(Name, Path, Size) \
+ FSlateImageBrush Name = IMAGE_BRUSH(TEXT(Path), Size); \
+ Name.Tiling = ESlateBrushTileType::NoTile; \
+ Name.ImageSize = Size; \
+ Name.DrawAs = ESlateBrushDrawType::Image; \
+ Name.ImageType = ESlateBrushImageType::FullColor; \
+
+
+void FAronaStyle::LoadConfig()
+{
+ TSharedRef Style = StyleInstance.ToSharedRef();
+
+ AddButtonStyle(CloseButtonStyleName);
+ AddFontInfo(DefaultFontName);
+ AddFloatValue(VolumeMeterBarSpace);
+ AddImageBrush(PianoRollBackground);
+ AddImageBrush(VolumeMeterBar);
+ AddImageBrush(WhiteBrush);
+ AddImageBrush(BlackKey);
+ AddImageBrush(WhiteKey);
+}
+
+void FAronaStyle::AddImageBrush(FName Key)
+{
+ TOptional ImageFileName = GetConfigValue(Key);
+ if (!ImageFileName)
+ return;
+ TOptional ImageSize = GetConfigValue(FName(Key.ToString() + "Size"));
+
+ const FString ImageFilePathName = StyleInstance->RootToContentDir(ImageFileName.GetValue(), TEXT(".png"));
+ StyleInstance->Set(Key, new FSlateImageBrush(ImageFilePathName, ImageSize.Get(FVector2f(16))));
+}
+
+void FAronaStyle::AddFloatValue(FName Key)
+{
+ TOptional Value = GetConfigValue(Key);
+ if (!Value)
+ return;
+ StyleInstance->Set(Key, Value.GetValue());
+}
+
+void FAronaStyle::AddFontInfo(FName Key)
+{
+ const TOptional FontName = GetConfigValue(Key);
+ if (!FontName)
+ return;
+ const TOptional FontSize = GetConfigValue(FName(Key.ToString() + "Size"));
+ StyleInstance->Set(Key, FSlateFontInfo(StyleInstance->RootToContentDir(FontName.GetValue(), TEXT(".ttf")), FontSize.Get(12)));
+}
+
+void FAronaStyle::AddButtonStyle(FName Key)
+{
+ const FString ButtonNormalName = Key.ToString() + "Normal";
+ const FString ButtonHoveredName = Key.ToString() + "Hovered";
+ const FString ButtonPressedName = Key.ToString() + "Pressed";
+ const TOptional ButtonNormal = GetConfigValue(FName(ButtonNormalName));
+ const TOptional ButtonHovered = GetConfigValue(FName(ButtonHoveredName));
+ const TOptional ButtonPressed = GetConfigValue(FName(ButtonPressedName));
+ const TOptional Size = GetConfigValue(FName(Key.ToString() + "Size"));
+
+ FButtonStyle ButtonStyle;
+ const FSlateImageBrush ButtonNormalBrush = FSlateImageBrush(StyleInstance->RootToContentDir(ButtonNormal.Get(""), TEXT(".png")), Size.Get(FVector2f(16)));
+ const FSlateImageBrush ButtonHoveredBrush = FSlateImageBrush(StyleInstance->RootToContentDir(ButtonHovered.Get(""), TEXT(".png")), Size.Get(FVector2f(16)));
+ const FSlateImageBrush ButtonPressedBrush = FSlateImageBrush(StyleInstance->RootToContentDir(ButtonPressed.Get(""), TEXT(".png")), Size.Get(FVector2f(16)));
+ ButtonStyle.SetNormal(ButtonNormalBrush).SetHovered(ButtonHoveredBrush).SetPressed(ButtonPressedBrush);
+ StyleInstance->Set(CloseButtonStyleName, ButtonStyle);
+}
+
+TSharedRef< FAronaStyle > FAronaStyle::Create()
+{
+ TSharedRef Style = MakeShareable(new FAronaStyle("AronaStyle"));
+
+ FString SkinName;
+ FAronaConfig::GetValue("Skin", "Skin", SkinName);
+ Style->SkinDir = FPaths::ProjectContentDir() / TEXT("Skin") / SkinName;
+ Style->Config.Read(Style->SkinDir / TEXT("Skin.ini"));
+
+ Style->SetContentRoot(Style->SkinDir);
+ return Style;
+}
+
+#undef IMAGE_BRUSH
+#undef BOX_BRUSH
+#undef BORDER_BRUSH
+#undef TTF_FONT
+#undef OTF_FONT
+
+void FAronaStyle::ReloadTextures()
+{
+ if (FSlateApplication::IsInitialized())
+ {
+ FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
+ }
+}
+
+const ISlateStyle& FAronaStyle::Get()
+{
+ return *StyleInstance;
+}
+
+const FName& FAronaStyle::GetStyleSetName() const
+{
+ static FName Name(TEXT("AronaModuleStyle"));
+ return Name;
+}
diff --git a/Source/Arona/UI/Style/AronaStyle.h b/Source/Arona/UI/Style/AronaStyle.h
new file mode 100644
index 0000000..488a1ef
--- /dev/null
+++ b/Source/Arona/UI/Style/AronaStyle.h
@@ -0,0 +1,146 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "ConfigCacheIni.h"
+#include "SlateTypes.h"
+#include "Styling/SlateStyle.h"
+
+inline FName CloseButtonStyleName("CloseButton");
+inline FName VolumeMeterBar("VolumeMeter");
+inline FName VolumeMeterBarSpace("VolumeMeterSpace");
+inline FName DefaultFontName("DefaultFont");
+inline FName PianoRollBackground("PianoRollBackground");
+inline FName WhiteBrush("WhiteBrush");
+inline FName WhiteKey("WhiteKey");
+inline FName BlackKey("BlackKey");
+
+/** */
+class FAronaStyle : public FSlateStyleSet
+{
+public:
+ FAronaStyle(const FName& InStyleSetName)
+ : FSlateStyleSet(InStyleSetName)
+ {
+ }
+
+ static void Initialize();
+
+ static void Shutdown();
+
+ /** reloads textures used by slate renderer */
+ static void ReloadTextures();
+
+ /** @return The Slate style set for the Shooter game */
+ static const ISlateStyle& Get();
+
+ virtual const FName& GetStyleSetName() const override;
+
+ static const FButtonStyle* GetButtonStyle(const FName& PropertyName, const ANSICHAR* Specifier = nullptr);
+ static const FSlateBrush* GetSlateBrush(const FName& PropertyName, const ANSICHAR* Specifier = nullptr);
+ static FSlateFontInfo GetFontInfo(const FName& PropertyName, const ANSICHAR* Specifier = nullptr);
+
+ template
+ static T GetValue(const FName& PropertyName, const ANSICHAR* Specifier = nullptr);
+
+ FString SkinDir;
+ FConfigFile Config;
+private:
+ void LoadConfig();
+ template
+ TOptional GetConfigValue(const FName& Key, FName FindSection = FName("Resource"));
+
+ void AddImageBrush(FName Key);
+ void AddFloatValue(FName Key);
+ void AddFontInfo(FName Key);
+ void AddButtonStyle(FName Key);
+
+ // static FConfigFile Config;
+ static TSharedRef Create();
+ static TSharedPtr StyleInstance;
+};
+
+template <>
+inline float FAronaStyle::GetValue(const FName& PropertyName, const ANSICHAR* Specifier)
+{
+ return StyleInstance->GetFloat(PropertyName, Specifier);
+}
+
+template <>
+inline FVector2D FAronaStyle::GetValue(const FName& PropertyName, const ANSICHAR* Specifier)
+{
+ return StyleInstance->GetVector(PropertyName, Specifier);
+}
+
+template <>
+inline const FLinearColor& FAronaStyle::GetValue(const FName& PropertyName, const ANSICHAR* Specifier)
+{
+ return StyleInstance->GetColor(PropertyName, Specifier);
+}
+
+template <>
+inline const FSlateColor FAronaStyle::GetValue(const FName& PropertyName, const ANSICHAR* Specifier)
+{
+ return StyleInstance->GetSlateColor(PropertyName, Specifier);
+}
+
+template <>
+inline const FMargin& FAronaStyle::GetValue(const FName& PropertyName, const ANSICHAR* Specifier)
+{
+ return StyleInstance->GetMargin(PropertyName, Specifier);
+}
+
+template<>
+inline TOptional FAronaStyle::GetConfigValue(const FName& Key, FName FindSection)
+{
+ TSharedRef Style = StaticCastSharedRef(StyleInstance.ToSharedRef());
+ if (!Style->Config.Contains(FindSection.ToString()))
+ return TOptional();
+ const FConfigSection* Section = Style->Config.Find(FindSection.ToString());
+ if (Section == nullptr)
+ return TOptional();
+ const FConfigValue* ConfigValue = Section->Find(Key);
+ if (ConfigValue == nullptr)
+ return TOptional();
+ return TOptional(ConfigValue->GetValue());
+}
+
+template<>
+inline TOptional FAronaStyle::GetConfigValue(const FName& Key, FName FindSection)
+{
+ TSharedRef Style = StaticCastSharedRef(StyleInstance.ToSharedRef());
+ if (!Style->Config.Contains(FindSection.ToString()))
+ return TOptional();
+ const FConfigSection* Section = Style->Config.Find(FindSection.ToString());
+ if (Section == nullptr)
+ return TOptional();
+ const FConfigValue* ConfigValue = Section->Find(Key);
+ if (ConfigValue == nullptr)
+ return TOptional();
+ FVector2f Value;
+ Value.InitFromString(ConfigValue->GetValue());
+ return TOptional(Value);
+}
+
+template<>
+inline TOptional FAronaStyle::GetConfigValue(const FName& Key, FName FindSection)
+{
+ TSharedRef Style = StaticCastSharedRef(StyleInstance.ToSharedRef());
+ if (!Style->Config.Contains(FindSection.ToString()))
+ return TOptional();
+ const FConfigSection* Section = Style->Config.Find(FindSection.ToString());
+ if (Section == nullptr)
+ return TOptional();
+ const FConfigValue* ConfigValue = Section->Find(Key);
+ if (ConfigValue == nullptr)
+ return TOptional();
+ FString String = ConfigValue->GetValue();
+ String = String.Replace(TEXT("x"), TEXT("X"));
+ String = String.Replace(TEXT("y"), TEXT("Y"));
+ String = String.Replace(TEXT(","), TEXT(""));
+ String = String.Replace(TEXT(","), TEXT(""));
+ return TOptional(FCString::Atof(*String));
+}
+
+
diff --git a/Source/Arona/UI/Widget/ChannelInterface/SChannelNode.cpp b/Source/Arona/UI/Widget/ChannelInterface/SChannelNode.cpp
new file mode 100644
index 0000000..5d14854
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelInterface/SChannelNode.cpp
@@ -0,0 +1,172 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SChannelNode.h"
+
+#include "MultiBoxBuilder.h"
+#include "SButton.h"
+#include "SChannelNodeButton.h"
+#include "SlateApplication.h"
+#include "SlateOptMacros.h"
+#include "SMenuAnchor.h"
+#include "SOverlay.h"
+#include "SSplitter.h"
+#include "STextBlock.h"
+#include "Singleton/MixerList.h"
+#include "Mixer/MixerTrack.h"
+#include "Widgets/SBoxPanel.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SChannelNode::Construct(const FArguments& InArgs, FChannelNode* InChannelNode, FChannelInterface* InNodeOwner, int32 NodeNameIndex)
+{
+ ChannelNode = InChannelNode;
+ ChannelNodeType = InArgs._ChannelNodeType;
+ NodeOwner = InNodeOwner;
+ NodeIndex = NodeNameIndex;
+
+
+ FText PortName = FText::FromString(GetNodeName(NodeNameIndex));
+
+ ChildSlot
+ [
+ SNew(SHorizontalBox)
+ +SHorizontalBox::Slot()
+ .FillWidth(1)
+ [
+ SAssignNew(PortTextBlock, STextBlock)
+ .Text(PortName)
+ ]
+ +SHorizontalBox::Slot()
+ .AutoWidth()
+ [
+ SAssignNew(ChangeNodeButton, SButton)
+ .OnClicked_Lambda([this]()
+ {
+ ShowNodeSelectMenu();
+ return FReply::Handled();
+ })
+ [
+ SAssignNew(NodeNameTextBlock, STextBlock)
+ .Text(FText::FromString(ChannelNode->GetName()))
+ ]
+ ]
+ ];
+}
+
+void SChannelNode::ShowNodeSelectMenu()
+{
+ FMenuBuilder MenuBuilder(true, nullptr);
+ MenuBuilder.AddWidget(
+ CreateNodeSelectMenu(),
+ FText()
+ );
+ auto Pos = ChangeNodeButton->GetTickSpaceGeometry().GetAbsolutePosition();
+ Pos.Y += ChangeNodeButton->GetTickSpaceGeometry().GetAbsoluteSize().Y;
+ FSlateApplication::Get().PushMenu(SharedThis(this), FWidgetPath(), MenuBuilder.MakeWidget(), Pos, FPopupTransitionEffect::ComboButton);
+}
+
+TSharedRef SChannelNode::CreateNodeSelectMenu()
+{
+ TSharedRef MenuBox = SNew(SVerticalBox);
+
+ MenuBox->AddSlot()
+ .AutoHeight()
+ [
+ SNew(SChannelNodeButton, FNullChannelNode::Get())
+ .OnClickedDelegate(this, &SChannelNode::OnMenuNodeSelected)
+ ];
+
+ FMixerList& MixerList = FMixerList::Get();
+ for (const FMixerTrack* Mixer : MixerList)
+ {
+ MenuBox->AddSlot()
+ .AutoHeight()
+ [
+ SNew(STextBlock)
+ .Text(FText::FromString(Mixer->GetName()))
+ ];
+ const TArray& MixerOutputNodes = Mixer->GetChannelInterface()->OutputChannelNodes;
+ for (FChannelNode* MixerChannelNode : MixerOutputNodes)
+ {
+ MenuBox->AddSlot()
+ .AutoHeight()
+ [
+ SNew(SChannelNodeButton, MixerChannelNode)
+ .OnClickedDelegate(this, &SChannelNode::OnMenuNodeSelected)
+ ];
+ }
+ }
+
+ return MenuBox;
+}
+
+void SChannelNode::OnMenuNodeSelected(FChannelNode* Node)
+{
+ check(NodeOwner);
+
+ switch (ChannelNodeType)
+ {
+ case EChannelNodeType::InputNode:
+ {
+ NodeIndex = NodeOwner->GetInputNodeIndex(ChannelNode);
+ NodeOwner->SetInputChannel(NodeIndex, Node);
+ break;
+ }
+ case EChannelNodeType::OutputNode:
+ {
+ NodeIndex = NodeOwner->GetOutputNodeIndex(ChannelNode);
+ NodeOwner->SetOutputChannel(NodeIndex, Node);
+ break;
+ }
+ default: ;
+ }
+
+ ChannelNode = Node;
+ NodeNameTextBlock->SetText(FText::FromString(Node->GetName()));
+}
+
+FString SChannelNode::GetNodeName(int32 NodeNameIndex)
+{
+ FString PortName;
+
+ TMap PortNames;
+
+ switch (ChannelNodeType)
+ {
+ case EChannelNodeType::InputNode:
+ PortNames = NodeOwner->GetInputChannelNodeName(ChannelNode);
+ break;
+ case EChannelNodeType::OutputNode:
+ PortNames = NodeOwner->GetOutputChannelNodeName(ChannelNode);
+ break;
+ default: ;
+ }
+
+ const FName* NameA = PortNames.Find(NodeNameIndex);
+ const FName* NameB = PortNames.Find(NodeNameIndex + 1);
+ if (NameA && NameB)
+ {
+ if (*NameA == *NameB)
+ PortName = NameA->ToString();
+ else
+ PortName = FString::Printf(TEXT("%s-%s"), *NameA->ToString(), *NameB->ToString());
+ }
+ else if (NameA)
+ {
+ PortName = NameA->ToString();
+ }
+ else if (NameB)
+ {
+ PortName = NameB->ToString();
+ }
+ else
+ {
+ PortName = TEXT("Null");
+ }
+
+ return PortName;
+}
+
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/ChannelInterface/SChannelNode.h b/Source/Arona/UI/Widget/ChannelInterface/SChannelNode.h
new file mode 100644
index 0000000..7d5aaed
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelInterface/SChannelNode.h
@@ -0,0 +1,49 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "AudioBuffer/ChannelNode.h"
+
+class SButton;
+class STextBlock;
+class SMenuAnchor;
+/**
+ *
+ */
+class ARONA_API SChannelNode : public SCompoundWidget
+{
+public:
+ enum class EChannelNodeType
+ {
+ InputNode,
+ OutputNode,
+ };
+
+ SLATE_BEGIN_ARGS(SChannelNode)
+ {
+ }
+ SLATE_ARGUMENT(EChannelNodeType, ChannelNodeType)
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FChannelNode* InChannelNode, FChannelInterface* InNodeOwner, int32 NodeNameIndex);
+
+ FChannelNode::FChannelNodeDelegate OnRightClickedDelegate;
+private:
+ void ShowNodeSelectMenu();
+ TSharedRef CreateNodeSelectMenu();
+ void OnMenuNodeSelected(FChannelNode* Node);
+ FString GetNodeName(int32 NodeNameIndex = -1);
+
+ FChannelInterface* NodeOwner = nullptr;
+ FChannelNode* ChannelNode = nullptr;
+ EChannelNodeType ChannelNodeType = EChannelNodeType::InputNode;
+
+ TSharedPtr ChangeNodeButton;
+ TSharedPtr NodeNameTextBlock;
+ TSharedPtr PortTextBlock;
+ int32 NodeIndex = -1;
+};
diff --git a/Source/Arona/UI/Widget/ChannelInterface/SChannelNodeButton.cpp b/Source/Arona/UI/Widget/ChannelInterface/SChannelNodeButton.cpp
new file mode 100644
index 0000000..9ae592e
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelInterface/SChannelNodeButton.cpp
@@ -0,0 +1,26 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SChannelNodeButton.h"
+
+#include "SButton.h"
+#include "SlateOptMacros.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+void SChannelNodeButton::Construct(const FArguments& InArgs, FChannelNode* InChannelNode)
+{
+ ChannelNode = InChannelNode;
+ OnClickedDelegate = InArgs._OnClickedDelegate;
+
+ ChildSlot
+ [
+ SNew(SButton)
+ .Text(FText::FromString(ChannelNode->GetName()))
+ .OnClicked_Lambda([this]() -> FReply
+ {
+ OnClickedDelegate.ExecuteIfBound(ChannelNode);
+ return FReply::Handled();
+ })
+ ];
+}
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/ChannelInterface/SChannelNodeButton.h b/Source/Arona/UI/Widget/ChannelInterface/SChannelNodeButton.h
new file mode 100644
index 0000000..6c2b877
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelInterface/SChannelNodeButton.h
@@ -0,0 +1,28 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "AudioBuffer/ChannelNode.h"
+
+/**
+ *
+ */
+class ARONA_API SChannelNodeButton : public SCompoundWidget
+{
+public:
+ SLATE_BEGIN_ARGS(SChannelNodeButton)
+ {}
+
+ SLATE_EVENT(FChannelNode::FChannelNodeDelegate, OnClickedDelegate)
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FChannelNode* InChannelNode);
+
+ FChannelNode::FChannelNodeDelegate OnClickedDelegate;
+private:
+ FChannelNode* ChannelNode = nullptr;
+};
diff --git a/Source/Arona/UI/Widget/ChannelInterface/SPluginHostChannelInterface.cpp b/Source/Arona/UI/Widget/ChannelInterface/SPluginHostChannelInterface.cpp
new file mode 100644
index 0000000..db17023
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelInterface/SPluginHostChannelInterface.cpp
@@ -0,0 +1,104 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SPluginHostChannelInterface.h"
+
+#include "SChannelNode.h"
+#include "SlateOptMacros.h"
+#include "SScrollBox.h"
+#include "SSpacer.h"
+#include "STextBlock.h"
+#include "AudioBuffer/ChannelInterface.h"
+#include "PluginHost/PluginHost.h"
+#include "Widgets/SBoxPanel.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SPluginHostChannelInterface::Construct(const FArguments& InArgs, FPluginHost* InPluginHost)
+{
+ PluginHost = InPluginHost;
+ const FChannelInterface* ChannelInterface = PluginHost->ChannelInterface;
+
+ InPluginHost->UpdateChannelNodeName();
+
+ const auto& InputNodes = ChannelInterface->InputChannelNodes;
+ const auto& OutputNodes = ChannelInterface->OutputChannelNodes;
+
+ TSharedPtr InputNodesBox;
+ TSharedPtr OutputNodesBox;
+ ChildSlot
+ [
+ SNew(SScrollBox)
+ +SScrollBox::Slot()
+ .AutoSize()
+ [
+ SNew(STextBlock)
+ .Text(FText::FromString("Input: "))
+ ]
+ +SScrollBox::Slot()
+ .AutoSize()
+ [
+ SAssignNew(InputNodesBox, SVerticalBox)
+ ]
+ +SScrollBox::Slot()
+ .AutoSize()
+ [
+ SNew(SSpacer)
+ .Size(FVector2D(1, 3))
+ ]
+ +SScrollBox::Slot()
+ .AutoSize()
+ [
+ SNew(STextBlock)
+ .Text(FText::FromString("Output: "))
+ ]
+ +SScrollBox::Slot()
+ .AutoSize()
+ [
+ SAssignNew(OutputNodesBox, SVerticalBox)
+ ]
+ ];
+
+
+ if (InputNodes.Num() > 0)
+ {
+ const TSharedRef DefaultInputNodeWidget = BuildChannelNode(InputNodes[0], SChannelNode::EChannelNodeType::InputNode, 0).ToSharedRef();
+ DefaultInputNodeWidget->SetEnabled(false);
+ InputNodesBox->AddSlot()
+ [
+ DefaultInputNodeWidget
+ ];
+ }
+ for (int32 i = 1; i < InputNodes.Num(); ++i)
+ {
+ InputNodesBox->AddSlot()
+ [
+ BuildChannelNode(InputNodes[i], SChannelNode::EChannelNodeType::InputNode, i * 2).ToSharedRef()
+ ];
+ }
+
+ if (OutputNodes.Num() > 0)
+ {
+ TSharedRef DefaultOutputNodeWidget = BuildChannelNode(OutputNodes[0], SChannelNode::EChannelNodeType::OutputNode, 0).ToSharedRef();
+ DefaultOutputNodeWidget->SetEnabled(false);
+ OutputNodesBox->AddSlot()
+ [
+ DefaultOutputNodeWidget
+ ];
+ }
+ for (int32 i = 1; i < OutputNodes.Num(); ++i)
+ {
+ OutputNodesBox->AddSlot()
+ [
+ BuildChannelNode(OutputNodes[i], SChannelNode::EChannelNodeType::OutputNode, i * 2).ToSharedRef()
+ ];
+ }
+}
+
+TSharedPtr SPluginHostChannelInterface::BuildChannelNode(FChannelNode* ChannelNode, SChannelNode::EChannelNodeType ChannelNodeType, int32 NodeNameIndex)
+{
+ return SNew(SChannelNode, ChannelNode, PluginHost->ChannelInterface, NodeNameIndex)
+ .ChannelNodeType(ChannelNodeType);
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/ChannelInterface/SPluginHostChannelInterface.h b/Source/Arona/UI/Widget/ChannelInterface/SPluginHostChannelInterface.h
new file mode 100644
index 0000000..fad1f38
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelInterface/SPluginHostChannelInterface.h
@@ -0,0 +1,31 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SChannelNode.h"
+#include "SCompoundWidget.h"
+
+class FPluginHost;
+class FChannelNode;
+class SChannelNode;
+class FChannelInterface;
+/**
+ *
+ */
+class ARONA_API SPluginHostChannelInterface : public SCompoundWidget
+{
+public:
+ SLATE_BEGIN_ARGS(SPluginHostChannelInterface)
+ {
+ }
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FPluginHost* InPluginHost);
+private:
+ TSharedPtr BuildChannelNode(FChannelNode* ChannelNode, SChannelNode::EChannelNodeType ChannelNodeType, int32 NodeNameIndex);
+
+ FPluginHost* PluginHost = nullptr;
+};
diff --git a/Source/Arona/UI/Widget/ChannelRack/ChannelRack.cpp b/Source/Arona/UI/Widget/ChannelRack/ChannelRack.cpp
new file mode 100644
index 0000000..2324ae3
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelRack/ChannelRack.cpp
@@ -0,0 +1,105 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "ChannelRack.h"
+
+#include "ChannelRackItem.h"
+#include "SlateOptMacros.h"
+#include "SScrollBox.h"
+#include "Singleton/PluginHostList.h"
+#include "Pattern/MidiPattern.h"
+#include "Singleton/MidiSequencer.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SChannelRack::Construct(const FArguments& InArgs)
+{
+ FPluginHostList::Get().OnInstrumentHostCreated.AddRaw(this, &SChannelRack::OnInstrumentHostCreated);
+ FPluginHostList::Get().OnPluginHostRemoved.AddRaw(this, &SChannelRack::OnInstrumentHostRemoved);
+ FPatternSelector::Get().OnPatternSelected.AddRaw(this, &SChannelRack::OnSelectPattern);
+
+ for (FPluginHost* PluginHost : FPluginHostList::Get().Instruments)
+ {
+ OnInstrumentHostCreated(PluginHost);
+ }
+
+ ChildSlot
+ [
+ SAssignNew(ListView, SScrollBox)
+ .AnimateWheelScrolling(true)
+ .ScrollBarThickness(FVector2D(2, 2))
+ ];
+
+ OnSelectPattern(FPatternSelector::Get().GetSelectedPattern());
+}
+
+void SChannelRack::SelectPattern(FMidiPattern* Pattern)
+{
+ TSharedPtr ScrollPanel = ListView->GetScrollPanel();
+ auto& Children = ScrollPanel->Children;
+ for (int i = 0; i < Children.Num(); ++i)
+ {
+ TSharedRef Item = StaticCastSharedRef(Children.GetChildAt(i));
+ Item->SetPattern(Pattern);
+ }
+}
+
+void SChannelRack::OnSelectPattern(FPattern* Pattern)
+{
+ if (!Pattern)
+ return;
+ if (Pattern->Type != EPatternType::Midi)
+ return;
+ SelectPattern((FMidiPattern*)Pattern);
+}
+
+void SChannelRack::UpdateSplitterAPosition(float A)
+{
+ TSharedPtr ScrollPanel = ListView->GetScrollPanel();
+ auto& Children = ScrollPanel->Children;
+ for (int i = 0; i < Children.Num(); ++i)
+ {
+ TSharedPtr Item = StaticCastSharedRef(Children.GetChildAt(i));
+ Item->SetSplliterASize(A);
+ }
+}
+
+void SChannelRack::UpdateSplitterBPosition(float B)
+{
+ TSharedPtr ScrollPanel = ListView->GetScrollPanel();
+ auto& Children = ScrollPanel->Children;
+ for (int i = 0; i < Children.Num(); ++i)
+ {
+ TSharedPtr Item = StaticCastSharedRef(Children.GetChildAt(i));
+ Item->SetSplliterBSize(B);
+ }
+}
+
+void SChannelRack::OnInstrumentHostCreated(FPluginHost* PluginHost)
+{
+ ListView->AddSlot()
+ .AutoSize()
+ .Padding(0, 0, 0, 10)
+ [
+ SNew(SChannelRackItem, PluginHost)
+ .OnSplliterAPositionChanged(this, &SChannelRack::UpdateSplitterAPosition)
+ .OnSplliterBPositionChanged(this, &SChannelRack::UpdateSplitterBPosition)
+ ];
+}
+
+void SChannelRack::OnInstrumentHostRemoved(FPluginHost* PluginHost)
+{
+ TSharedPtr ScrollPanel = ListView->GetScrollPanel();
+ FChildren* Children = ScrollPanel->GetChildren();
+ for (int i = 0; i < Children->Num(); ++i)
+ {
+ const TSharedRef ChannelRackItem = StaticCastSharedRef(Children->GetChildAt(i));
+ if (ChannelRackItem->GetPluginHost() == PluginHost)
+ {
+ ListView->RemoveSlot(ChannelRackItem);
+ break;
+ }
+ }
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/ChannelRack/ChannelRack.h b/Source/Arona/UI/Widget/ChannelRack/ChannelRack.h
new file mode 100644
index 0000000..e1db70f
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelRack/ChannelRack.h
@@ -0,0 +1,43 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "ChannelRackItem.h"
+#include "SCompoundWidget.h"
+#include "SListView.h"
+#include "UI/Widget/IChildWindow.h"
+
+class FPattern;
+class FMidiPattern;
+class SScrollBox;
+class FPluginHost;
+
+/**
+ *
+ */
+class ARONA_API SChannelRack : public SCompoundWidget, public IChildWindow
+{
+public:
+ SLATE_BEGIN_ARGS(SChannelRack)
+ {
+ }
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs);
+
+ virtual TSharedRef GetWidget() override { return AsShared(); }
+
+ void SelectPattern(FMidiPattern* Pattern);
+private:
+ void OnSelectPattern(FPattern* Pattern);
+ void UpdateSplitterAPosition(float A);
+ void UpdateSplitterBPosition(float B);
+
+ void OnInstrumentHostCreated(FPluginHost* PluginHost);
+ void OnInstrumentHostRemoved(FPluginHost* PluginHost);
+
+ TSharedPtr ListView;
+};
diff --git a/Source/Arona/UI/Widget/ChannelRack/ChannelRackItem.cpp b/Source/Arona/UI/Widget/ChannelRack/ChannelRackItem.cpp
new file mode 100644
index 0000000..4ef8648
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelRack/ChannelRackItem.cpp
@@ -0,0 +1,143 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "ChannelRackItem.h"
+
+#include "ChannelRackMidiThumbnail.h"
+#include "MultiBoxBuilder.h"
+#include "SBox.h"
+#include "SButton.h"
+#include "SImage.h"
+#include "SlateApplication.h"
+#include "SlateOptMacros.h"
+#include "SSplitter.h"
+#include "PluginHost/PluginHost.h"
+#include "Singleton/PluginHostList.h"
+#include "UI/Widget/WindowManager.h"
+#include "UI/Widget/ChannelInterface/SPluginHostChannelInterface.h"
+#include "Widgets/SBoxPanel.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+#define LOCTEXT_NAMESPACE "FChannelRack"
+
+void SChannelRackItem::Construct(const FArguments& InArgs, FPluginHost* InPluginHost)
+{
+ PluginHost = InPluginHost;
+
+ ChildSlot
+ [
+ SAssignNew(Splitter, SSplitter)
+ .ResizeMode(ESplitterResizeMode::FixedSize)
+
+ +SSplitter::Slot()
+ .OnSlotResized(InArgs._OnSplliterAPositionChanged)
+ .MinSize(32)
+ [
+ SNew(SHorizontalBox)
+ +SHorizontalBox::Slot()
+ .AutoWidth()
+ [
+ SNew(SCheckBox)
+ .IsChecked(PluginHost->IsEnabled() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked)
+ .OnCheckStateChanged(this, &SChannelRackItem::SetPluginHostEnabled)
+ ]
+ +SHorizontalBox::Slot()
+ .FillWidth(1.f)
+ .VAlign(VAlign_Top)
+ [
+ SNew(SButton)
+ .Text(FText::FromString(PluginHost->Name))
+ .OnClicked(this, &SChannelRackItem::TogglePluginHostEditor)
+ ]
+ ]
+
+ +SSplitter::Slot()
+ .OnSlotResized(InArgs._OnSplliterBPositionChanged)
+ [
+ SNew(SBox)
+ .HeightOverride(64)
+ [
+ SAssignNew(MidiThumbnail, SChannelRackMidiThumbnail, PluginHost)
+ .Pattern(nullptr)
+ ]
+ ]
+ ];
+}
+
+FReply SChannelRackItem::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::RightMouseButton)
+ {
+ ShowPluginHostMenu();
+ return FReply::Handled();
+ }
+ return FReply::Unhandled();
+}
+
+void SChannelRackItem::SetPattern(FMidiPattern* InPattern)
+{
+ MidiThumbnail->SetPattern(InPattern);
+}
+
+void SChannelRackItem::SetSplliterASize(float X)
+{
+ Splitter->SlotAt(0).SetSizeValue(X);
+}
+
+void SChannelRackItem::SetSplliterBSize(float X)
+{
+ Splitter->SlotAt(1).SetSizeValue(X);
+}
+
+void SChannelRackItem::ShowPluginHostMenu()
+{
+ FMenuBuilder MenuBuilder(true, nullptr);
+ // MenuBuilder.BeginSection("ChannelRackItem", FText::FromString("ChannelRackItem"));
+ MenuBuilder.AddMenuEntry(
+ LOCTEXT("OpenChannelInterface", "打开通道面板"),
+ LOCTEXT("OpenChannelInterface_ToolTip", "打开一个通道面板窗口"),
+ FSlateIcon(),
+ FUIAction(FExecuteAction::CreateRaw(this, &SChannelRackItem::ShowPluginHostChannelInterface))
+ );
+
+ MenuBuilder.AddMenuEntry(
+ LOCTEXT("DeletePluginHost", "删除插件"),
+ FText(),
+ FSlateIcon(),
+ FUIAction(FExecuteAction::CreateRaw(this, &SChannelRackItem::DeletePluginHost))
+ );
+
+ // MenuBuilder.EndSection();
+
+ FSlateApplication::Get().PushMenu(SharedThis(this), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ContextMenu);
+}
+
+void SChannelRackItem::SetPluginHostEnabled(ECheckBoxState CheckBoxState)
+{
+ PluginHost->SetEnabled(CheckBoxState == ECheckBoxState::Checked);
+}
+
+FReply SChannelRackItem::TogglePluginHostEditor()
+{
+ FWindowManager::Get().TogglePluginEditor(PluginHost);
+ return FReply::Handled();
+}
+
+void SChannelRackItem::ShowPluginHostChannelInterface()
+{
+ FMenuBuilder MenuBuilder(true, nullptr);
+ MenuBuilder.AddWidget(
+ SNew(SPluginHostChannelInterface, PluginHost),
+ FText()
+ );
+ FSlateApplication::Get().PushMenu(SharedThis(this), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ComboButton);
+}
+
+void SChannelRackItem::DeletePluginHost()
+{
+ FPluginHostList::Get().RemoveInstrument(PluginHost);
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
+#undef LOCTEXT_NAMESPACE
diff --git a/Source/Arona/UI/Widget/ChannelRack/ChannelRackItem.h b/Source/Arona/UI/Widget/ChannelRack/ChannelRackItem.h
new file mode 100644
index 0000000..a7f03d8
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelRack/ChannelRackItem.h
@@ -0,0 +1,55 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "CurveSequence.h"
+#include "SCompoundWidget.h"
+#include "SCheckBox.h"
+
+class SSplitter;
+class SImage;
+class SChannelRackMidiThumbnail;
+class FMidiPattern;
+class FPluginHost;
+/**
+ *
+ */
+class ARONA_API SChannelRackItem : public SCompoundWidget
+{
+public:
+ DECLARE_DELEGATE_OneParam(FSetter, float);
+
+ SLATE_BEGIN_ARGS(SChannelRackItem)
+ {
+ }
+
+ SLATE_EVENT(FSetter, OnSplliterAPositionChanged)
+ SLATE_EVENT(FSetter, OnSplliterBPositionChanged)
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FPluginHost* InPluginHost);
+ virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+
+ void SetPattern(FMidiPattern* InPattern);
+ FPluginHost* GetPluginHost() const { return PluginHost; }
+
+ void SetSplliterASize(float X);
+ void SetSplliterBSize(float X);
+private:
+
+ void ShowPluginHostMenu();
+ void SetPluginHostEnabled(ECheckBoxState CheckBoxState);
+ FReply TogglePluginHostEditor();
+
+ void ShowPluginHostChannelInterface();
+ void DeletePluginHost();
+
+ FPluginHost* PluginHost = nullptr;
+ FMidiPattern* Pattern = nullptr;
+
+ TSharedPtr MidiThumbnail;
+ TSharedPtr Splitter;
+};
diff --git a/Source/Arona/UI/Widget/ChannelRack/ChannelRackMidiThumbnail.cpp b/Source/Arona/UI/Widget/ChannelRack/ChannelRackMidiThumbnail.cpp
new file mode 100644
index 0000000..6395ef5
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelRack/ChannelRackMidiThumbnail.cpp
@@ -0,0 +1,124 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "ChannelRackMidiThumbnail.h"
+
+#include "SImage.h"
+#include "SInvalidationPanel.h"
+#include "SlateApplication.h"
+#include "SlateOptMacros.h"
+#include "SScrollBox.h"
+#include "SViewport.h"
+#include "Midi/MidiMessageSequence.h"
+#include "Singleton/MidiSequencer.h"
+#include "UI/Widget/MainWindow.h"
+#include "UI/Widget/SUpdatableImage.h"
+#include "UI/Widget/Thumbnail.h"
+#include "UI/Widget/WindowManager.h"
+#include "UI/Widget/PianoRoll/SPianoRoll.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+SChannelRackMidiThumbnail::~SChannelRackMidiThumbnail()
+{
+ SetPattern(nullptr);
+}
+
+void SChannelRackMidiThumbnail::SetPattern(FMidiPattern* InPattern)
+{
+ if (CurrentPattern)
+ {
+ CurrentPattern->OnChanged.RemoveAll(this);
+ CurrentPattern->OnPlay.RemoveAll(this);
+ }
+ if (!InPattern)
+ return;
+ CurrentPattern = InPattern;
+ CurrentPattern->OnChanged_MainThread.AddRaw(this, &SChannelRackMidiThumbnail::OnChanged);
+ CurrentPattern->OnPlay.AddRaw(this, &SChannelRackMidiThumbnail::OnPatternPlay);
+ OnChanged(PluginHost, &InPattern->GetSequence(PluginHost));
+}
+
+void SChannelRackMidiThumbnail::Construct(const FArguments& InArgs, FPluginHost* InPluginHost)
+{
+ PluginHost = InPluginHost;
+ SetPattern(InArgs._Pattern);
+
+ ChildSlot
+ [
+ SNew(SInvalidationPanel)
+ [
+ SAssignNew(UpdatableImage, SUpdatableImage)
+ .OnPostResize(this, &SChannelRackMidiThumbnail::UpdateMidiThumbnail)
+ .UpdateInterval(0)
+ ]
+ ];
+
+ if (InArgs._Pattern)
+ OnChanged(PluginHost, &InArgs._Pattern->GetSequence(InPluginHost));
+}
+
+FReply SChannelRackMidiThumbnail::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (!CurrentPattern)
+ return FReply::Unhandled();
+ FMidiMessageSequence* MidiSequence = &CurrentPattern->GetSequence(PluginHost);
+ TSharedPtr PianoRoll = SNew(SPianoRoll, MidiSequence, PluginHost);
+
+
+ FWindowManager::Get().GetMainWindow()->CreateChildWindow(
+ FVector2D(100, 100),
+ TEXT(""),
+ PianoRoll.ToSharedRef()
+ );
+ PianoRoll->InitScrollBar();
+ return FReply::Unhandled();
+}
+
+int32 SChannelRackMidiThumbnail::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
+{
+ LayerId = SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
+ if (CurrentPattern)
+ {
+ const double EndTime = CurrentPattern->GetLength();
+ const double CurrentPercent = LastPatternPos / EndTime * (double)AllottedGeometry.Size.X;
+ TArray Points;
+ Points.Add(FVector2f(CurrentPercent, 0));
+ Points.Add(FVector2f(CurrentPercent, AllottedGeometry.Size.Y));
+ FSlateDrawElement::MakeLines(
+ OutDrawElements,
+ ++LayerId,
+ AllottedGeometry.ToPaintGeometry(),
+ Points,
+ ESlateDrawEffect::None,
+ FLinearColor::Red,
+ true,
+ 1.f
+ );
+ }
+ return LayerId;
+}
+
+void SChannelRackMidiThumbnail::OnChanged(FPluginHost* Host, FMidiMessageSequence* Changed)
+{
+ if (Host != PluginHost)
+ return;
+ UpdatableImage->NeedRedraw();
+}
+
+void SChannelRackMidiThumbnail::OnPatternPlay(FPatternInstance* PatternInstance, AudioFrame PatternTick, uint32 Length)
+{
+ LastPatternPos = PatternTick;
+}
+
+void SChannelRackMidiThumbnail::UpdateMidiThumbnail(FImageData& ImageData)
+{
+ if (!CurrentPattern)
+ return;
+ const FMidiMessageSequence* MidiSequence = &CurrentPattern->GetSequence(PluginHost);
+
+ ImageData.ClearColor(FColor::Black);
+ Thumbnail::GenerateMidiThumbnail(MidiSequence, ImageData);
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/ChannelRack/ChannelRackMidiThumbnail.h b/Source/Arona/UI/Widget/ChannelRack/ChannelRackMidiThumbnail.h
new file mode 100644
index 0000000..7fe3c9c
--- /dev/null
+++ b/Source/Arona/UI/Widget/ChannelRack/ChannelRackMidiThumbnail.h
@@ -0,0 +1,48 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "SLeafWidget.h"
+#include "Pattern/MidiPattern.h"
+#include "UI/Widget/SUpdatableImage.h"
+
+class SUpdatableImage;
+class FPluginHost;
+
+/**
+ *
+ */
+class ARONA_API SChannelRackMidiThumbnail : public SCompoundWidget
+{
+public:
+ SLATE_BEGIN_ARGS(SChannelRackMidiThumbnail)
+ {
+ }
+ SLATE_ARGUMENT(FMidiPattern*, Pattern)
+
+ SLATE_END_ARGS()
+
+ ~SChannelRackMidiThumbnail();
+ void SetPattern(FMidiPattern* InPattern);
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FPluginHost* InPluginHost);
+
+ virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
+private:
+ void OnChanged(FPluginHost* Host, FMidiMessageSequence* Changed);
+ void OnPatternPlay(FPatternInstance* PatternInstance, AudioFrame PatternTick, uint32 Length);
+
+ void UpdateMidiThumbnail(FImageData& ImageData);
+
+ FPluginHost* PluginHost;
+ FMidiPattern* CurrentPattern;
+
+ TSharedPtr UpdatableImage;
+
+ AudioFrame LastPatternPos;
+};
+
diff --git a/Source/Arona/UI/Widget/IChildWindow.h b/Source/Arona/UI/Widget/IChildWindow.h
new file mode 100644
index 0000000..ad213eb
--- /dev/null
+++ b/Source/Arona/UI/Widget/IChildWindow.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "CoreMinimal.h"
+
+class SWidget;
+
+class IChildWindow
+{
+public:
+ virtual ~IChildWindow() = default;
+ virtual TSharedPtr GetFocusWidget() { return nullptr; }
+ virtual TSharedRef GetWidget() = 0;
+};
diff --git a/Source/Arona/UI/Widget/MainWindow.cpp b/Source/Arona/UI/Widget/MainWindow.cpp
new file mode 100644
index 0000000..3d89374
--- /dev/null
+++ b/Source/Arona/UI/Widget/MainWindow.cpp
@@ -0,0 +1,198 @@
+#include "MainWindow.h"
+
+#include "IChildWindow.h"
+#include "SBackgroundBlur.h"
+#include "SChildWindow.h"
+#include "SMainWindowHeader.h"
+#include "SConstraintCanvas.h"
+#include "SlateApplication.h"
+#include "SMainWindow.h"
+#include "SWindow.h"
+#include "SWindowTitleBar.h"
+#include "WaveformViewer.h"
+#include "ChannelRack/ChannelRack.h"
+#include "Thread/MainThreadEventList.h"
+#include "Thread/ThreadMessage.h"
+#include "Mixer/SMixer.h"
+#include "PlayList/SPlayList.h"
+
+#define LOCTEXT_NAMESPACE "Arona"
+
+DECLARE_THREAD_MESSAGE(FMainThreadEventList, PostCreateChildWindow,
+ FMainWindow* Window;
+ TSharedPtr ChildWindow;
+)
+{
+ Args.Window->FrontChildWindow(Args.ChildWindow);
+}
+
+void FMainWindow::Init()
+{
+ auto NewTab = SNew(SDockTab);
+ TabManager = FGlobalTabmanager::Get()->NewTabManager(NewTab);
+ TArray TabNames = {"Tab0", "Tab1", "Tab2"};
+ auto Layout = FTabManager::NewLayout(TEXT("TestLayout"))
+ ->AddArea(
+ FTabManager::NewPrimaryArea()
+ ->SetOrientation(Orient_Horizontal)
+ ->Split(
+ FTabManager::NewStack()
+ ->AddTab(TabNames[0], ETabState::Type::OpenedTab)
+ )
+ ->Split(
+ FTabManager::NewStack()
+ ->AddTab(TabNames[1], ETabState::Type::OpenedTab)
+ )
+ );
+
+ TabManager->RegisterTabSpawner(TabNames[0], FOnSpawnTab::CreateLambda([](const FSpawnTabArgs& Args) -> TSharedRef
+ {
+ return SNew(SDockTab)
+ .TabRole(ETabRole::NomadTab)
+ [
+ SNew(SButton)
+ ];
+ }));
+
+ TabManager->RegisterTabSpawner(TabNames[1], FOnSpawnTab::CreateRaw(this, &FMainWindow::CreatePlayListTab));
+
+
+ MainWindow = SNew(SMainWindow)
+ .CreateTitleBar(false)
+ .AutoCenter(EAutoCenter::PrimaryWorkArea)
+ .ClientSize(FVector2D(1270, 720));
+
+ const auto WindowTitleBar = SNew(SWindowTitleBar, MainWindow.ToSharedRef(), nullptr, EHorizontalAlignment::HAlign_Fill)
+ .ShowAppIcon(false);
+
+ MainWindow->SetTitleBar(WindowTitleBar);
+ MainWindow->SetContent(
+ SNew(SVerticalBox)
+ +SVerticalBox::Slot()
+ .AutoHeight()
+ [
+ WindowTitleBar
+ ]
+ +SVerticalBox::Slot()
+ .AutoHeight()
+ [
+ SNew(SMainWindowHeader)
+ .OnChannelRackClicked_Raw(this, &FMainWindow::ToggleChannelRack)
+ .OnMixerClicked_Raw(this, &FMainWindow::ToggleMixer)
+ ]
+ +SVerticalBox::Slot()
+ [
+ SNew(SOverlay)
+ +SOverlay::Slot()
+ [
+ TabManager->RestoreFrom(Layout, MainWindow).ToSharedRef()
+ ]
+ +SOverlay::Slot()
+ [
+ SAssignNew(MainWindowCanvas, SConstraintCanvas)
+ ]
+ +SOverlay::Slot()
+ [
+ SNew(SHorizontalBox)
+ +SHorizontalBox::Slot()
+ [
+ SNew(SWaveformViewer)
+ .Visibility(EVisibility::SelfHitTestInvisible)
+ ].FillWidth(1.f)
+ // +SHorizontalBox::Slot()
+ // [
+ // SNew(SWaveformViewer)
+ // .Visibility(EVisibility::SelfHitTestInvisible)
+ // ].FillWidth(1.f)
+ ]
+ ]
+ );
+
+ FSlateApplication::Get().AddWindow(MainWindow.ToSharedRef());
+
+ InitChildWindow();
+}
+
+TSharedPtr FMainWindow::CreateChildWindow(FVector2D Size, FString Title, TSharedPtr Content, bool IsSingletonWindow)
+{
+ auto* PanelChildren = static_cast*>(MainWindowCanvas->GetChildren());
+
+ TSharedPtr Out;
+ auto Slot = MainWindowCanvas->AddSlot();
+ Slot.ZOrder(PanelChildren->Num() + 2);
+ Slot.AttachWidget(SAssignNew(Out, SChildWindow, Slot.GetSlot())
+ .IsSingletonWindow(IsSingletonWindow)
+ .Title(Title)
+ .ResizeHandleSize(FVector2D(16, 16))
+ .Content(Content)
+ );
+
+ Slot.Offset(FMargin(0, 0, Size.X, Size.Y));
+
+ PUSH_THREAD_EVENT(PostCreateChildWindow, this, Out);
+ return Out;
+}
+
+void FMainWindow::FrontChildWindow(TSharedPtr ChildWindow)
+{
+ const auto& PanelChildren = MainWindowCanvas->GetPanelChildren();
+ const TArray>& Children = PanelChildren.GetAllChildren();
+ for (auto& Slot : Children)
+ {
+ Slot->SetZOrder(Slot->GetZOrder() - 1);
+ }
+ ChildWindow->GetSlot()->SetZOrder(PanelChildren.Num());
+ FWidgetPath WidgetPath;
+
+ const TSharedPtr FocusWidget = ChildWindow->Content->GetFocusWidget();
+ if (FocusWidget.IsValid())
+ {
+ FSlateApplication::Get().SetAllUserFocus(FocusWidget);
+ FSlateApplication::Get().SetKeyboardFocus(FocusWidget);
+ }
+ else
+ {
+ FSlateApplication::Get().SetAllUserFocus(ChildWindow->Content->GetWidget());
+ FSlateApplication::Get().SetKeyboardFocus(ChildWindow->Content->GetWidget());
+ }
+}
+
+TSharedPtr FMainWindow::GetChannelRack()
+{
+ return ChannelRack;
+}
+
+TSharedRef FMainWindow::CreatePlayListTab(const FSpawnTabArgs& Args)
+{
+ return SNew(SDockTab)
+ .TabRole(ETabRole::NomadTab)
+ .Label(LOCTEXT("PlayListTabTitle", "PlayList"))
+ [
+ SNew(SPlayList)
+ ];
+}
+
+void FMainWindow::InitChildWindow()
+{
+ ChannelRackWindow = CreateChildWindow(FVector2D(300, 600), "ChannelRack", SAssignNew(ChannelRack, SChannelRack), true);
+ MixerWindow = CreateChildWindow(FVector2D(600, 400), "Mixer", SNew(SMixer), true);
+}
+
+void FMainWindow::ToggleChildWindow(TSharedPtr ChildWindow)
+{
+ if (ChildWindow->GetVisibility() != EVisibility::Visible)
+ ChildWindow->SetVisibility(EVisibility::Visible);
+ else
+ ChildWindow->SetVisibility(EVisibility::Collapsed);
+}
+
+void FMainWindow::ToggleChannelRack()
+{
+ ToggleChildWindow(ChannelRackWindow);
+}
+
+void FMainWindow::ToggleMixer()
+{
+ ToggleChildWindow(MixerWindow);
+}
+#undef LOCTEXT_NAMESPACE
diff --git a/Source/Arona/UI/Widget/MainWindow.h b/Source/Arona/UI/Widget/MainWindow.h
new file mode 100644
index 0000000..6a8cc46
--- /dev/null
+++ b/Source/Arona/UI/Widget/MainWindow.h
@@ -0,0 +1,38 @@
+#pragma once
+#include "Events.h"
+#include "WidgetPath.h"
+
+class IChildWindow;
+class SChannelRack;
+class SChildWindow;
+class SConstraintCanvas;
+class SWindow;
+class SWidget;
+
+class FMainWindow
+{
+public:
+ void Init();
+ TSharedPtr CreateChildWindow(FVector2D Size, FString Title, TSharedPtr Content, bool IsSingletonWindow = false);
+ void FrontChildWindow(TSharedPtr ChildWindow);
+
+ TSharedPtr MainWindow;
+ TSharedPtr MainWindowCanvas;
+
+ TSharedPtr GetChannelRack();
+private:
+ TSharedRef CreatePlayListTab(const FSpawnTabArgs& Args);
+
+ void InitChildWindow();
+
+ void ToggleChildWindow(TSharedPtr ChildWindow);
+
+ void ToggleChannelRack();
+ void ToggleMixer();
+
+ TSharedPtr ChannelRackWindow;
+ TSharedPtr ChannelRack;
+
+ TSharedPtr MixerWindow;
+ TSharedPtr TabManager;
+};
diff --git a/Source/Arona/UI/Widget/Mixer/SMixer.cpp b/Source/Arona/UI/Widget/Mixer/SMixer.cpp
new file mode 100644
index 0000000..b3a2684
--- /dev/null
+++ b/Source/Arona/UI/Widget/Mixer/SMixer.cpp
@@ -0,0 +1,264 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SMixer.h"
+
+#include "MultiBoxBuilder.h"
+#include "SMixerTrack.h"
+#include "SlateOptMacros.h"
+#include "SListView.h"
+#include "SMixerEffectList.h"
+#include "SScrollBox.h"
+#include "Singleton/MixerList.h"
+
+#define LOCTEXT_NAMESPACE "SMixer"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void FMixerSelector::AddTrack(FMixerTrack* MixerTrack)
+{
+ if (SelectedTracks.Contains(MixerTrack))
+ return;
+ SelectedTracks.Add(MixerTrack);
+ OnMixerTrackSelected.Broadcast(MixerTrack);
+}
+
+bool FMixerSelector::RemoveTrack(FMixerTrack* MixerTrack)
+{
+ if (!SelectedTracks.Contains(MixerTrack))
+ return false;
+ SelectedTracks.Remove(MixerTrack);
+ OnMixerTrackDeselected.Broadcast(MixerTrack);
+ return true;
+}
+
+void FMixerSelector::UnselectAll()
+{
+ for (FMixerTrack* MixerTrack : SelectedTracks)
+ {
+ OnMixerTrackDeselected.Broadcast(MixerTrack);
+ }
+ SelectedTracks.Empty();
+}
+
+SMixer::~SMixer()
+{
+ FMixerList& MixerList = FMixerList::Get();
+ MixerList.OnMixerTrackCreated.RemoveAll(this);
+ MixerList.OnMixerTrackRemoved.RemoveAll(this);
+}
+
+void SMixer::Construct(const FArguments& InArgs)
+{
+ FMixerList& MixerList = FMixerList::Get();
+
+ MixerList.OnMixerTrackCreated.AddRaw(this, &SMixer::OnMixerTrackCreated);
+ MixerList.OnMixerTrackRemoved.AddRaw(this, &SMixer::OnMixerTrackRemoved);
+
+ Selector.OnMixerTrackSelected.AddRaw(this, &SMixer::OnMixerTrackSelected);
+ Selector.OnMixerTrackDeselected.AddRaw(this, &SMixer::OnMixerTrackDeselected);
+
+ ChildSlot
+ [
+ SNew(SHorizontalBox)
+ +SHorizontalBox::Slot()
+ .FillWidth(1.f)
+ [
+ SAssignNew(ListView, SScrollBox)
+ .AnimateWheelScrolling(true)
+ .Orientation(EOrientation::Orient_Horizontal)
+ .ScrollBarThickness(FVector2D(2))
+ ]
+ +SHorizontalBox::Slot()
+ .AutoWidth()
+ [
+ SNew(SBox)
+ .WidthOverride(200)
+ [
+ SAssignNew(EffectList, SMixerEffectList)
+ ]
+ ]
+ ];
+
+ for (FMixerTrack* Mixer : MixerList)
+ {
+ OnMixerTrackCreated(Mixer);
+ }
+}
+
+FReply SMixer::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::RightMouseButton)
+ {
+ FMenuBuilder MenuBuilder(true, nullptr);
+ MenuBuilder.AddMenuEntry(
+ LOCTEXT("AddDummyMixerTrack", "创建傀儡轨道"),
+ LOCTEXT("AddDummyMixerTrack_Tooltip", "创建一个新的傀儡轨道"),
+ FSlateIcon(),
+ FUIAction(FExecuteAction::CreateLambda([this]()
+ {
+ FMixerList& MixerList = FMixerList::Get();
+ MixerList.CreateDummyTrack("Dummy");
+ }))
+ );
+
+ FSlateApplication::Get().PushMenu(SharedThis(this), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ContextMenu);
+ }
+ else if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
+ {
+ Selector.UnselectAll();
+ EffectList->SetMixerTrack(nullptr);
+ }
+ return FReply::Unhandled();
+}
+
+FReply SMixer::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
+{
+ if (InKeyEvent.GetKey() == EKeys::LeftShift || InKeyEvent.GetKey() == EKeys::RightShift)
+ {
+ bShiftDown = true;
+ }
+
+ if (InKeyEvent.GetKey() == EKeys::Delete)
+ {
+ for (FMixerTrack* MixerTrack : Selector.GetSelectedTracks())
+ {
+ FMixerList::Get().RemoveTrack(MixerTrack);
+ }
+ Selector.UnselectAll();
+ }
+ return FReply::Unhandled();
+}
+
+FReply SMixer::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
+{
+ if (InKeyEvent.GetKey() == EKeys::LeftShift || InKeyEvent.GetKey() == EKeys::RightShift)
+ {
+ bShiftDown = false;
+ }
+ return FReply::Unhandled();
+}
+
+void SMixer::OnMixerTrackCreated(FMixerTrack* MixerTrack)
+{
+ ListView->AddSlot()
+ [
+ SNew(SMixerTrack)
+ .MixerTrack(MixerTrack)
+ .OnClicked(this, &SMixer::OnMixerTrackClicked)
+ ];
+}
+
+void SMixer::OnMixerTrackRemoved(FMixerTrack* MixerTrack)
+{
+ if (Selector.RemoveTrack(MixerTrack))
+ {
+ Selector.AddTrack(FMixerList::Get().GetMaster());
+ }
+
+ ForeachMixerTrackWidget([&, this](TSharedRef MixerTrackWidget)
+ {
+ if (MixerTrackWidget->GetMixerTrack() == MixerTrack)
+ {
+ ListView->RemoveSlot(MixerTrackWidget);
+ return false;
+ }
+ return true;
+ });
+
+}
+
+void SMixer::OnMixerTrackClicked(FMixerTrack* InMixerTrack)
+{
+ Selector.UnselectAll();
+
+ if (bShiftDown)
+ {
+ const TArray& Selected = Selector.GetSelectedTracks();
+ if (Selected.Num() > 0)
+ {
+ const TSharedPtr ScrollPanel = ListView->GetScrollPanel();
+ FChildren* Children = ScrollPanel->GetChildren();
+ for (int32 i = 0; i < Children->Num(); i++)
+ {
+ TSharedRef Child = Children->GetChildAt(i);
+ const TSharedRef MixerTrackWidget = StaticCastSharedRef(Child);
+ if (MixerTrackWidget->GetMixerTrack() == Selected[0])
+ {
+ int32 StartIndex = i;
+ for (int32 j = 0; j < Children->Num(); j++)
+ {
+ TSharedRef Child2 = Children->GetChildAt(j);
+ const TSharedRef MixerTrackWidget2 = StaticCastSharedRef(Child2);
+ if (MixerTrackWidget2->GetMixerTrack() == InMixerTrack)
+ {
+ int32 EndIndex = j;
+ if (StartIndex > EndIndex)
+ {
+ const int32 Temp = StartIndex;
+ StartIndex = EndIndex;
+ EndIndex = Temp;
+ }
+ for (int32 k = StartIndex; k <= EndIndex; k++)
+ {
+ TSharedRef Child3 = Children->GetChildAt(k);
+ const TSharedRef MixerTrackWidget3 = StaticCastSharedRef(Child3);
+ Selector.AddTrack(MixerTrackWidget3->GetMixerTrack());
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ Selector.AddTrack(InMixerTrack);
+ EffectList->SetMixerTrack(InMixerTrack);
+ }
+}
+
+void SMixer::OnMixerTrackSelected(FMixerTrack* InMixerTrack)
+{
+ ForeachMixerTrackWidget([&, this](TSharedRef MixerTrackWidget)
+ {
+ if (MixerTrackWidget->GetMixerTrack() == InMixerTrack)
+ {
+ MixerTrackWidget->SetSelected(true);
+ return false;
+ }
+ return true;
+ });
+}
+
+void SMixer::OnMixerTrackDeselected(FMixerTrack* InMixerTrack)
+{
+ ForeachMixerTrackWidget([&, this](TSharedRef MixerTrackWidget)
+ {
+ if (MixerTrackWidget->GetMixerTrack() == InMixerTrack)
+ {
+ MixerTrackWidget->SetSelected(false);
+ return false;
+ }
+ return true;
+ });
+}
+
+void SMixer::ForeachMixerTrackWidget(TFunction)> InFunction)
+{
+ const TSharedPtr ScrollPanel = ListView->GetScrollPanel();
+ FChildren* Children = ScrollPanel->GetChildren();
+ for (int32 i = 0; i < Children->Num(); i++)
+ {
+ TSharedRef Child = Children->GetChildAt(i);
+ const TSharedRef MixerTrackWidget = StaticCastSharedRef(Child);
+ if (!InFunction(MixerTrackWidget))
+ break;
+ }
+}
+
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
+#undef LOCTEXT_NAMESPACE
diff --git a/Source/Arona/UI/Widget/Mixer/SMixer.h b/Source/Arona/UI/Widget/Mixer/SMixer.h
new file mode 100644
index 0000000..45c603f
--- /dev/null
+++ b/Source/Arona/UI/Widget/Mixer/SMixer.h
@@ -0,0 +1,65 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "SMixerTrack.h"
+#include "Mixer/MixerTrack.h"
+#include "UI/Widget/IChildWindow.h"
+
+class SScrollBox;
+class SMixerEffectList;
+
+DECLARE_MULTICAST_DELEGATE_OneParam(FMixerTrackDelegate, FMixerTrack*)
+
+class FMixerSelector
+{
+public:
+ void AddTrack(FMixerTrack* MixerTrack);
+ bool RemoveTrack(FMixerTrack* MixerTrack);
+ void UnselectAll();
+
+ const TArray& GetSelectedTracks() const { return SelectedTracks; }
+
+ FMixerTrackDelegate OnMixerTrackSelected;
+ FMixerTrackDelegate OnMixerTrackDeselected;
+private:
+ TArray SelectedTracks;
+};
+
+/**
+ *
+ */
+class ARONA_API SMixer : public SCompoundWidget, public IChildWindow
+{
+public:
+ ~SMixer();
+ SLATE_BEGIN_ARGS(SMixer)
+ {
+ }
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs);
+ virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
+ virtual FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
+
+ virtual TSharedRef GetWidget() override { return AsShared(); }
+protected:
+ void OnMixerTrackCreated(FMixerTrack* MixerTrack);
+ void OnMixerTrackRemoved(FMixerTrack* MixerTrack);
+ void OnMixerTrackClicked(FMixerTrack* InMixerTrack);
+
+ void OnMixerTrackSelected(FMixerTrack* InMixerTrack);
+ void OnMixerTrackDeselected(FMixerTrack* InMixerTrack);
+
+ void ForeachMixerTrackWidget(TFunction)> InFunction);
+private:
+ TSharedPtr ListView;
+ TSharedPtr EffectList;
+ FMixerSelector Selector;
+ bool bShiftDown = false;
+};
diff --git a/Source/Arona/UI/Widget/Mixer/SMixerEffectItem.cpp b/Source/Arona/UI/Widget/Mixer/SMixerEffectItem.cpp
new file mode 100644
index 0000000..17ec188
--- /dev/null
+++ b/Source/Arona/UI/Widget/Mixer/SMixerEffectItem.cpp
@@ -0,0 +1,99 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SMixerEffectItem.h"
+
+#include "MultiBoxBuilder.h"
+#include "SButton.h"
+#include "SlateApplication.h"
+#include "SlateOptMacros.h"
+#include "PluginHost/PluginHost.h"
+#include "Singleton/PluginHostList.h"
+#include "Widgets/SBoxPanel.h"
+#include "UI/Widget/WindowManager.h"
+#include "UI/Widget/ChannelInterface/SPluginHostChannelInterface.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+#define LOCTEXT_NAMESPACE "SMixer"
+
+void SMixerEffectItem::Construct(const FArguments& InArgs, FPluginHost* InPluginHost)
+{
+ PluginHost = InPluginHost;
+
+ ChildSlot
+ [
+ SNew(SHorizontalBox)
+ +SHorizontalBox::Slot()
+ .FillWidth(1.f)
+ [
+ SNew(SButton)
+ .Text(FText::FromString(PluginHost->Name))
+ .OnClicked(this, &SMixerEffectItem::OnButtonClicked)
+ ]
+ +SHorizontalBox::Slot()
+ .AutoWidth()
+ [
+ SAssignNew(MenuAnchor, SMenuAnchor)
+ .OnGetMenuContent(this, &SMixerEffectItem::CreateChannelInterfaceMenu)
+ [
+ SNew(SButton)
+ .Text(FText::FromString("X"))
+ .OnClicked(this, &SMixerEffectItem::OnChannelInterfaceClicked)
+ ]
+ ]
+ ];
+}
+
+FReply SMixerEffectItem::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::RightMouseButton)
+ {
+ ShowMenu();
+ }
+ return FReply::Handled();
+}
+
+FReply SMixerEffectItem::OnButtonClicked()
+{
+ FWindowManager::Get().TogglePluginEditor(PluginHost);
+ return FReply::Handled();
+}
+
+FReply SMixerEffectItem::OnChannelInterfaceClicked()
+{
+ MenuAnchor->SetIsOpen(true);
+ return FReply::Handled();
+}
+
+TSharedRef SMixerEffectItem::CreateChannelInterfaceMenu()
+{
+ return SNew(SPluginHostChannelInterface, PluginHost);
+}
+
+void SMixerEffectItem::ShowMenu()
+{
+ FMenuBuilder MenuBuilder(true, nullptr);
+ // Delete effect
+ MenuBuilder.AddMenuEntry(
+ LOCTEXT("DeleteEffect", "删除效果器"),
+ LOCTEXT("DeleteEffectTooltip", "从混音轨道中删除该效果。"),
+ FSlateIcon(),
+ FUIAction(
+ FExecuteAction::CreateLambda([this]()
+ {
+ FPluginHostList::Get().RemovePluginHost(PluginHost);
+ })
+ )
+ );
+ FSlateApplication::Get().PushMenu(
+ AsShared(),
+ FWidgetPath(),
+ MenuBuilder.MakeWidget(),
+ FSlateApplication::Get().GetCursorPos(),
+ FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu)
+ );
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
+#undef LOCTEXT_NAMESPACE
diff --git a/Source/Arona/UI/Widget/Mixer/SMixerEffectItem.h b/Source/Arona/UI/Widget/Mixer/SMixerEffectItem.h
new file mode 100644
index 0000000..ae62d62
--- /dev/null
+++ b/Source/Arona/UI/Widget/Mixer/SMixerEffectItem.h
@@ -0,0 +1,33 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+
+class SMenuAnchor;
+class FPluginHost;
+/**
+ *
+ */
+class ARONA_API SMixerEffectItem : public SCompoundWidget
+{
+public:
+ SLATE_BEGIN_ARGS(SMixerEffectItem)
+ {}
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FPluginHost* InPluginHost);
+
+ virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ FPluginHost* PluginHost;
+private:
+ FReply OnButtonClicked();
+ FReply OnChannelInterfaceClicked();
+ TSharedRef CreateChannelInterfaceMenu();
+
+ void ShowMenu();
+
+ TSharedPtr MenuAnchor;
+};
diff --git a/Source/Arona/UI/Widget/Mixer/SMixerEffectList.cpp b/Source/Arona/UI/Widget/Mixer/SMixerEffectList.cpp
new file mode 100644
index 0000000..d78750c
--- /dev/null
+++ b/Source/Arona/UI/Widget/Mixer/SMixerEffectList.cpp
@@ -0,0 +1,123 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SMixerEffectList.h"
+
+#include "DesktopPlatformModule.h"
+#include "SButton.h"
+#include "SlateOptMacros.h"
+#include "SMixerEffectItem.h"
+#include "SScrollBox.h"
+#include "Singleton/MixerList.h"
+#include "Mixer/MixerTrack.h"
+#include "Singleton/PluginHostList.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+SMixerEffectList::~SMixerEffectList()
+{
+ FMixerList::Get().OnMixerTrackEffectAdded.RemoveAll(this);
+ // FMixerList::Get().OnMixerTrackEffectRemoved.RemoveAll(this);
+ FMixerList::Get().OnMixerTrackRemoved.RemoveAll(this);
+}
+
+void SMixerEffectList::Construct(const FArguments& InArgs)
+{
+ FMixerList::Get().OnMixerTrackRemoved.AddRaw(this, &SMixerEffectList::OnMixerTrackRemoved);
+ FMixerList::Get().OnMixerTrackEffectAdded.AddRaw(this, &SMixerEffectList::OnMixerTrackEffectAdded);
+ // FMixerList::Get().OnMixerTrackEffectRemoved.AddRaw(this, &SMixerEffectList::OnMixerTrackEffectRemoved);
+ FPluginHostList::Get().OnPluginHostRemoved.AddRaw(this, &SMixerEffectList::OnMixerTrackEffectRemoved);
+
+ ChildSlot
+ [
+ SAssignNew(ScrollBox, SScrollBox)
+ .Orientation(Orient_Vertical)
+ .AnimateWheelScrolling(true)
+ .Visibility(EVisibility::SelfHitTestInvisible)
+ +SScrollBox::Slot()
+ [
+ SAssignNew(VerticalBox, SVerticalBox)
+ ]
+ +SScrollBox::Slot()
+ [
+ SAssignNew(AddEffectButton, SButton)
+ .Text(FText::FromString("Add Effect"))
+ .OnClicked(this, &SMixerEffectList::AddNewEffect)
+ .IsEnabled(false)
+ ]
+ ];
+}
+
+void SMixerEffectList::SetMixerTrack(FMixerTrack* InMixerTrack)
+{
+ if (MixerTrack == InMixerTrack)
+ return;
+ VerticalBox->ClearChildren();
+ MixerTrack = InMixerTrack;
+ if (!MixerTrack)
+ {
+ AddEffectButton->SetEnabled(false);
+ return;
+ }
+
+ AddEffectButton->SetEnabled(true);
+ for (FPluginHost* Effect : MixerTrack->Effects)
+ {
+ AddEffectItemWidget(Effect);
+ }
+}
+
+void SMixerEffectList::OnMixerTrackEffectAdded(FMixerTrack* InMixerTrack, FPluginHost* InPluginHost)
+{
+ if (MixerTrack != InMixerTrack)
+ return;
+ AddEffectItemWidget(InPluginHost);
+}
+
+void SMixerEffectList::OnMixerTrackEffectRemoved(FPluginHost* InPluginHost)
+{
+ const int32 NumSlots = VerticalBox->NumSlots();
+ for (int i = 0; i < NumSlots; ++i)
+ {
+ SVerticalBox::FSlot& Slot = VerticalBox->GetSlot(i);
+ const TSharedRef& Widget = Slot.GetWidget();
+ TSharedRef EffectItem = StaticCastSharedRef(Widget);
+ if (EffectItem->PluginHost == InPluginHost)
+ {
+ VerticalBox->RemoveSlot(EffectItem);
+ break;
+ }
+ }
+}
+
+void SMixerEffectList::OnMixerTrackRemoved(FMixerTrack* InMixerTrack)
+{
+ if (MixerTrack != InMixerTrack)
+ return;
+ VerticalBox->ClearChildren();
+}
+
+void SMixerEffectList::AddEffectItemWidget(FPluginHost* InPluginHost)
+{
+ VerticalBox->AddSlot()
+ [
+ SNew(SMixerEffectItem, InPluginHost)
+ ];
+}
+
+FReply SMixerEffectList::AddNewEffect()
+{
+ IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
+ FString FileTypes = TEXT("Dynamic Link Library (*.dll)|*.dll");
+ TArray OutFiles;
+ DesktopPlatform->OpenFileDialog(nullptr, TEXT("Choose a DLL"), TEXT(""), TEXT(""), FileTypes, EFileDialogFlags::None, OutFiles);
+ if (OutFiles.Num() == 0)
+ return FReply::Handled();
+ FPluginHost* EffectPlugin = FPluginHostList::Get().TryLoadPlugin(OutFiles[0]);
+ if (!EffectPlugin)
+ return FReply::Handled();
+ MixerTrack->AddEffect(EffectPlugin);
+ return FReply::Handled();
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/Mixer/SMixerEffectList.h b/Source/Arona/UI/Widget/Mixer/SMixerEffectList.h
new file mode 100644
index 0000000..d47a795
--- /dev/null
+++ b/Source/Arona/UI/Widget/Mixer/SMixerEffectList.h
@@ -0,0 +1,44 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "PluginHost/PluginHost.h"
+
+class SButton;
+class SVerticalBox;
+class SScrollBox;
+class FMixerTrack;
+
+/**
+ *
+ */
+class ARONA_API SMixerEffectList : public SCompoundWidget
+{
+public:
+ ~SMixerEffectList();
+ SLATE_BEGIN_ARGS(SMixerEffectList)
+ {
+ }
+
+ SLATE_END_ARGS()
+
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs);
+
+ void SetMixerTrack(FMixerTrack* InMixerTrack);
+private:
+ void OnMixerTrackEffectAdded(FMixerTrack* InMixerTrack, FPluginHost* InPluginHost);
+ void OnMixerTrackEffectRemoved(FPluginHost* InPluginHost);
+ void OnMixerTrackRemoved(FMixerTrack* InMixerTrack);
+ void AddEffectItemWidget(FPluginHost* InPluginHost);
+
+ FReply AddNewEffect();
+
+ TSharedPtr ScrollBox;
+ TSharedPtr VerticalBox;
+ TSharedPtr AddEffectButton;
+ FMixerTrack* MixerTrack;
+};
diff --git a/Source/Arona/UI/Widget/Mixer/SMixerTrack.cpp b/Source/Arona/UI/Widget/Mixer/SMixerTrack.cpp
new file mode 100644
index 0000000..cfb4aa7
--- /dev/null
+++ b/Source/Arona/UI/Widget/Mixer/SMixerTrack.cpp
@@ -0,0 +1,158 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SMixerTrack.h"
+
+#include "MultiBoxBuilder.h"
+#include "SBorder.h"
+#include "SlateApplication.h"
+#include "SlateOptMacros.h"
+
+#include "Mixer/MixerTrack.h"
+
+#include "SSlider.h"
+#include "STextBlock.h"
+#include "Singleton/MixerList.h"
+#include "Singleton/PluginHostList.h"
+#include "UI/Widget/SVolumeMeterBar.h"
+#include "Widgets/SBoxPanel.h"
+
+#include "DSP/Dsp.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+#define LOCTEXT_NAMESPACE "SMixerTrack"
+
+void SMixerTrack::Construct(const FArguments& InArgs)
+{
+ MixerTrack = InArgs._MixerTrack;
+ OnClicked = InArgs._OnClicked;
+ FText Name = FText::FromString(MixerTrack->GetName());
+ ChildSlot
+ [
+ SNew(SOverlay)
+ +SOverlay::Slot()
+ [
+ SAssignNew(Border, SBorder)
+ .Visibility(EVisibility::Collapsed)
+ .BorderImage(&White)
+ ]
+
+ +SOverlay::Slot()
+ [
+ SNew(SVerticalBox)
+ +SVerticalBox::Slot()
+ .FillHeight(0.3f)
+ [
+ SNew(STextBlock)
+ .OverflowPolicy(ETextOverflowPolicy::Ellipsis)
+ .Text(Name)
+ .WrapTextAt(1)
+ ]
+ +SVerticalBox::Slot()
+ .FillHeight(1.f)
+ [
+ SNew(SHorizontalBox)
+ +SHorizontalBox::Slot()
+ [
+ SNew(SVolumeMeterBar)
+ .Width(5)
+ .MinValue(-96.f)
+ .MaxValue(6.f)
+ .MeterValue(this, &SMixerTrack::MeterValue)
+ ]
+ +SHorizontalBox::Slot()
+ [
+ SNew(SSlider)
+ .Orientation(EOrientation::Orient_Vertical)
+ .MinValue(-96.f)
+ .MaxValue(10.f)
+ .Value(Audio::ConvertToDecibels(MixerTrack->Gain))
+ .OnValueChanged(this, &SMixerTrack::OnVolumeChanged)
+ ]
+ ]
+ ]
+ ];
+}
+
+FReply SMixerTrack::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
+ {
+ OnClicked.ExecuteIfBound(MixerTrack);
+ return FReply::Handled();
+ }
+
+ if (MouseEvent.GetEffectingButton() == EKeys::RightMouseButton)
+ {
+ ShowMenu();
+ }
+ return FReply::Unhandled();
+}
+
+void SMixerTrack::SetSelected(bool bInSelected)
+{
+ Border->SetVisibility(bInSelected ? EVisibility::SelfHitTestInvisible : EVisibility::Collapsed);
+}
+
+void SMixerTrack::ShowMenu()
+{
+ FMenuBuilder MenuBuilder(true, nullptr);
+
+ if (MixerTrack->Type == EMixerTrackType::Dummy)
+ {
+ MenuBuilder.AddMenuEntry(
+ LOCTEXT("DeleteTrack", "删除轨道"),
+ LOCTEXT("DeleteTrack", "删除轨道"),
+ FSlateIcon(),
+ FUIAction(FExecuteAction::CreateRaw(this, &SMixerTrack::DeleteTrack))
+ );
+ }
+ else
+ {
+ MenuBuilder.AddMenuEntry(
+ LOCTEXT("DeleteTrack", "删除乐器轨道"),
+ LOCTEXT("DeleteTrack", "删除乐器轨道(这将会导致删除乐器)"),
+ FSlateIcon(),
+ FUIAction(FExecuteAction::CreateRaw(this, &SMixerTrack::DeleteInstrument))
+ );
+ }
+
+ FSlateApplication::Get().PushMenu(
+ AsShared(),
+ FWidgetPath(),
+ MenuBuilder.MakeWidget(),
+ FSlateApplication::Get().GetCursorPos(),
+ FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu)
+ );
+}
+
+void SMixerTrack::DeleteTrack()
+{
+ FMixerList::Get().RemoveTrack(MixerTrack);
+}
+
+void SMixerTrack::DeleteInstrument()
+{
+ FInstrumentMixerTrack* InstrumentMixerTrack = static_cast(MixerTrack);
+ FPluginHostList::Get().RemoveInstrument(InstrumentMixerTrack->GetHost());
+}
+
+TArray SMixerTrack::MeterValue() const
+{
+ TArray Out;
+ Out.Reset(2);
+ for (int i = 0; i < 2; ++i)
+ {
+ Out.Add(MixerTrack->GetPeak(i));
+ }
+ return Out;
+}
+
+void SMixerTrack::OnVolumeChanged(float X)
+{
+ MixerTrack->Gain = Audio::ConvertToLinear(X);
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
+#undef LOCTEXT_NAMESPACE
diff --git a/Source/Arona/UI/Widget/Mixer/SMixerTrack.h b/Source/Arona/UI/Widget/Mixer/SMixerTrack.h
new file mode 100644
index 0000000..ccbf385
--- /dev/null
+++ b/Source/Arona/UI/Widget/Mixer/SMixerTrack.h
@@ -0,0 +1,51 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+
+class SBorder;
+class SMixer;
+class FMixerTrack;
+
+DECLARE_DELEGATE_OneParam(FMixerTrackEvent, FMixerTrack*)
+
+/**
+ *
+ */
+class ARONA_API SMixerTrack : public SCompoundWidget
+{
+public:
+ SLATE_BEGIN_ARGS(SMixerTrack)
+ {
+ }
+
+ SLATE_ARGUMENT(FMixerTrack*, MixerTrack)
+
+ SLATE_EVENT(FMixerTrackEvent, OnClicked)
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs);
+
+ virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+
+ FMixerTrack* GetMixerTrack() const { return MixerTrack; }
+
+ void SetSelected(bool bInSelected);
+private:
+ void ShowMenu();
+ void DeleteTrack();
+ void DeleteInstrument();
+
+ TArray MeterValue() const;
+ void OnVolumeChanged(float X);
+
+ bool LeftMouseButtonDown = false;
+ FMixerTrackEvent OnClicked;
+ FMixerTrack* MixerTrack = nullptr;
+ TSharedPtr Border;
+ FSlateColorBrush White = FSlateColorBrush(FColor::White);
+};
diff --git a/Source/Arona/UI/Widget/Pattern/SPatternInstance.cpp b/Source/Arona/UI/Widget/Pattern/SPatternInstance.cpp
new file mode 100644
index 0000000..69df8e0
--- /dev/null
+++ b/Source/Arona/UI/Widget/Pattern/SPatternInstance.cpp
@@ -0,0 +1,160 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SPatternInstance.h"
+
+#include "SButton.h"
+#include "SInvalidationPanel.h"
+#include "SlateOptMacros.h"
+#include "STextBlock.h"
+#include "SViewport.h"
+#include "Pattern/PatternInstance.h"
+#include "Render/UpdatableTexture.h"
+#include "UI/Widget/SUpdatableTexture.h"
+#include "Widgets/SBoxPanel.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SPatternInstance::Construct(const FArguments& InArgs)
+{
+ PatternInstance = InArgs._PatternInstance;
+ FrameToPixel = InArgs._FrameToPixel;
+ SnapFrame = InArgs._SnapFrame;
+
+ ChildSlot
+ [
+ SNew(SOverlay)
+ +SOverlay::Slot()
+ [
+ SNew(SBorder)
+ .BorderBackgroundColor(FLinearColor(0, 0, 0, 0.3f))
+ ]
+
+ +SOverlay::Slot()
+ [
+ SNew(SVerticalBox)
+ +SVerticalBox::Slot()
+ .AutoHeight()
+ [
+ SNew(SHorizontalBox)
+ +SHorizontalBox::Slot()
+ .AutoWidth()
+ [
+ SNew(SButton)
+ .Text(FText::FromString("X"))
+ .OnClicked(this, &SPatternInstance::OpenPatternMenu)
+ ]
+ +SHorizontalBox::Slot()
+ .FillWidth(1.f)
+ .VAlign(VAlign_Center)
+ [
+ SNew(STextBlock)
+ .Text(FText::FromString(PatternInstance->GetOwner()->Name))
+ .OverflowPolicy(ETextOverflowPolicy::Ellipsis)
+ .Justification(ETextJustify::Left)
+ ]
+ ]
+ +SVerticalBox::Slot()
+ .FillHeight(1.f)
+ [
+ InArgs._View
+ ]
+ ]
+ ];
+}
+
+FReply SPatternInstance::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (ResizeDirection != ResizeDir::None)
+ {
+ FPatternSelector::Get().SelectPatternInstance(PatternInstance);
+ const TRange& Range = PatternInstance->TimeRange;
+ BeginPatternStart = Range.GetLowerBoundValue();
+ BeginPatternEnd = Range.GetUpperBoundValue();
+ MouseDownPos = MouseEvent.GetScreenSpacePosition();
+ BeginPatternPos = PatternInstance->Pos;
+ return FReply::Handled().CaptureMouse(AsShared());
+ }
+ return FReply::Unhandled();
+}
+
+FReply SPatternInstance::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (ResizeDirection != ResizeDir::None)
+ {
+ PatternInstance->RequestEndSetting();
+ return FReply::Handled().ReleaseMouseCapture();
+ }
+ return FReply::Unhandled();
+}
+
+FReply SPatternInstance::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ const FVector2f LocalMousePos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
+
+ if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
+ {
+ const float MouseDelta = (MouseEvent.GetScreenSpacePosition().X - MouseDownPos.X) / MyGeometry.Scale;
+ const float Scaler = FrameToPixel.Get();
+ const bool NoSnap = MouseEvent.GetModifierKeys().IsAltDown();
+ double Delta = MouseDelta / Scaler;
+ if (!NoSnap)
+ Delta = FMath::GridSnap(Delta, SnapFrame.Get());
+
+ switch (ResizeDirection)
+ {
+ case ResizeDir::None: break;
+ case ResizeDir::Left:
+ {
+ AudioFrame NewRangeStart = BeginPatternStart + Delta;
+ AudioFrame NewPos = BeginPatternPos + Delta;
+ if (NewRangeStart.Pos < 0)
+ {
+ NewPos -= NewRangeStart;
+ NewRangeStart = 0;
+ }
+ if (NewPos.Pos < 0)
+ {
+ NewRangeStart -= NewPos;
+ NewPos = 0;
+ }
+ PatternInstance->TimeRange.SetLowerBoundValue(NewRangeStart);
+ PatternInstance->SetMidiPos(NewPos.Ticks());
+ return FReply::Handled();
+ }
+ case ResizeDir::Right:
+ {
+ const AudioFrame NewRangeEnd = FMath::Max(0, BeginPatternEnd + Delta);
+ PatternInstance->TimeRange.SetUpperBoundValue(NewRangeEnd);
+ return FReply::Handled();
+ }
+ default: ;
+ }
+ }
+ else
+ {
+ if (LocalMousePos.X <= ResizeHandleSize)
+ {
+ ResizeDirection = ResizeDir::Left;
+ }
+ else if (LocalMousePos.X >= MyGeometry.GetLocalSize().X - ResizeHandleSize)
+ {
+ ResizeDirection = ResizeDir::Right;
+ }
+ else
+ {
+ ResizeDirection = ResizeDir::None;
+ }
+ switch (ResizeDirection)
+ {
+ case ResizeDir::None: SetCursor(EMouseCursor::Default); break;
+ case ResizeDir::Left:
+ case ResizeDir::Right: SetCursor(EMouseCursor::ResizeLeftRight); break;
+ default: ;
+ }
+ }
+
+ return FReply::Unhandled();
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/Pattern/SPatternInstance.h b/Source/Arona/UI/Widget/Pattern/SPatternInstance.h
new file mode 100644
index 0000000..e59905c
--- /dev/null
+++ b/Source/Arona/UI/Widget/Pattern/SPatternInstance.h
@@ -0,0 +1,71 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "Singleton/MidiSequencer.h"
+
+class SUpdatableTexture;
+class FPatternInstance;
+class FUpdatableTexture;
+
+struct FPatternInstanceClickData
+{
+ FPatternInstance* PatternInstance;
+ double MidiTimestampOffset;
+};
+
+DECLARE_DELEGATE_RetVal_OneParam(FReply, FPatternInstanceClickDelegate, FPatternInstanceClickData)
+
+/**
+ *
+ */
+class ARONA_API SPatternInstance : public SCompoundWidget
+{
+public:
+
+ enum class ResizeDir
+ {
+ None,
+ Left,
+ Right,
+ };
+ SLATE_BEGIN_ARGS(SPatternInstance)
+ {}
+
+ SLATE_ARGUMENT(FPatternInstance*, PatternInstance)
+ SLATE_ATTRIBUTE(float, FrameToPixel)
+
+ SLATE_ATTRIBUTE(AudioFrame, SnapFrame)
+ SLATE_ARGUMENT(TSharedRef, View)
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs);
+
+ virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+
+ FPatternInstance* GetPatternInstance() const { return PatternInstance; }
+
+ float ResizeHandleSize = 5.f;
+protected:
+ virtual FReply OpenPatternMenu() { return FReply::Unhandled(); }
+
+ ResizeDir ResizeDirection = ResizeDir::None;
+
+ FPatternInstance* PatternInstance = nullptr;
+
+ TAttribute FrameToPixel;
+ TAttribute SnapFrame;
+
+ FVector2f MouseDownPos; // 屏幕坐标
+ AudioFrame BeginPatternEnd;
+ AudioFrame BeginPatternStart;
+ AudioFrame BeginPatternPos;
+
+ mutable FVector2f LastSize;
+};
diff --git a/Source/Arona/UI/Widget/Pattern/SWaveformPatternInstance.cpp b/Source/Arona/UI/Widget/Pattern/SWaveformPatternInstance.cpp
new file mode 100644
index 0000000..dd92109
--- /dev/null
+++ b/Source/Arona/UI/Widget/Pattern/SWaveformPatternInstance.cpp
@@ -0,0 +1 @@
+#include "SWaveformPatternInstance.h"
diff --git a/Source/Arona/UI/Widget/Pattern/SWaveformPatternInstance.h b/Source/Arona/UI/Widget/Pattern/SWaveformPatternInstance.h
new file mode 100644
index 0000000..50d83cb
--- /dev/null
+++ b/Source/Arona/UI/Widget/Pattern/SWaveformPatternInstance.h
@@ -0,0 +1,8 @@
+#pragma once
+#include "SPatternInstance.h"
+
+class ARONA_API SWaveformPatternInstance : public SPatternInstance
+{
+public:
+
+};
diff --git a/Source/Arona/UI/Widget/PatternThumbnail/SMidiPatternThumbnail.cpp b/Source/Arona/UI/Widget/PatternThumbnail/SMidiPatternThumbnail.cpp
new file mode 100644
index 0000000..6721065
--- /dev/null
+++ b/Source/Arona/UI/Widget/PatternThumbnail/SMidiPatternThumbnail.cpp
@@ -0,0 +1,71 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SMidiPatternThumbnail.h"
+
+#include "SInvalidationPanel.h"
+#include "SlateOptMacros.h"
+#include "Render/UpdatableTexture.h"
+#include "Pattern/MidiPattern.h"
+#include "PluginHost/PluginHost.h"
+#include "UI/Widget/SUpdatableImage.h"
+#include "UI/Widget/Thumbnail.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+
+SMidiPatternThumbnail::~SMidiPatternThumbnail()
+{
+ if (FMidiPattern* Pattern = (FMidiPattern*)GetPattern())
+ Pattern->OnChanged.RemoveAll(this);
+}
+
+void SMidiPatternThumbnail::Construct(const FArguments& InArgs)
+{
+ ChildSlot
+ [
+ SNew(SInvalidationPanel)
+ [
+ SAssignNew(UpdatableImage, SUpdatableImage)
+ .OnPostResize(this, &SMidiPatternThumbnail::UpdateMidiThumbnail)
+ ]
+ ];
+}
+
+void SMidiPatternThumbnail::Redraw()
+{
+ OnChanged(nullptr, nullptr);
+}
+
+void SMidiPatternThumbnail::OnPatternChanged(FPattern* OldPattern, FPattern* NewPattern)
+{
+ FMidiPattern* OldMidiPattern = (FMidiPattern*)OldPattern;
+ FMidiPattern* NewMidiPattern = (FMidiPattern*)NewPattern;
+ check(NewPattern->Type == EPatternType::Midi)
+
+ if (OldMidiPattern)
+ OldMidiPattern->OnChanged.RemoveAll(this);
+
+ if (!NewMidiPattern)
+ return;
+ NewMidiPattern->OnChanged_MainThread.AddRaw(this, &SMidiPatternThumbnail::OnChanged);
+}
+
+void SMidiPatternThumbnail::OnChanged(FPluginHost* Host, FMidiMessageSequence* Changed)
+{
+ if (!GetPattern())
+ return;
+ UpdatableImage->NeedRedraw();
+}
+
+void SMidiPatternThumbnail::UpdateMidiThumbnail(FImageData& ImageData)
+{
+ if (!GetPattern())
+ return;
+
+ ImageData.ClearColor(FColor::Black);
+ FMidiPattern* Pattern = (FMidiPattern*)GetPattern();
+ Thumbnail::GenerateMidiPatternThumbnail(Pattern, ImageData, FColor::White);
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/PatternThumbnail/SMidiPatternThumbnail.h b/Source/Arona/UI/Widget/PatternThumbnail/SMidiPatternThumbnail.h
new file mode 100644
index 0000000..bad1fef
--- /dev/null
+++ b/Source/Arona/UI/Widget/PatternThumbnail/SMidiPatternThumbnail.h
@@ -0,0 +1,32 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "SPatternThumbnail.h"
+
+class SUpdatableImage;
+struct FImageData;
+/**
+ *
+ */
+class ARONA_API SMidiPatternThumbnail : public SPatternThumbnail
+{
+public:
+ ~SMidiPatternThumbnail();
+ SLATE_BEGIN_ARGS(SMidiPatternThumbnail)
+ {
+ }
+ SLATE_END_ARGS()
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs);
+ virtual void Redraw() override;
+protected:
+ void OnPatternChanged(FPattern* OldPattern, FPattern* NewPattern);
+private:
+ void OnChanged(FPluginHost* Host, FMidiMessageSequence* Changed);
+ void UpdateMidiThumbnail(FImageData& ImageData);
+
+ TSharedPtr UpdatableImage;
+};
diff --git a/Source/Arona/UI/Widget/PatternThumbnail/SPatternSelector.cpp b/Source/Arona/UI/Widget/PatternThumbnail/SPatternSelector.cpp
new file mode 100644
index 0000000..dc94e7c
--- /dev/null
+++ b/Source/Arona/UI/Widget/PatternThumbnail/SPatternSelector.cpp
@@ -0,0 +1,93 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SPatternSelector.h"
+
+#include "SPatternThumbnail.h"
+#include "SInvalidationPanel.h"
+#include "SlateOptMacros.h"
+#include "SMenuAnchor.h"
+#include "SScrollBox.h"
+#include "Singleton/MidiSequencer.h"
+#include "UI/Widget/ChannelRack/ChannelRackMidiThumbnail.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SPatternSelector::Construct(const FArguments& InArgs)
+{
+ FPatternSelector::Get().OnPatternSelected.AddRaw(this, &SPatternSelector::OnPatternSelected);
+ FPatternSelector::Get().OnPatternDeselected.AddRaw(this, &SPatternSelector::OnPatternDeselected);
+ PatternList = SNew(SScrollBox);
+ ChildSlot
+ [
+ SAssignNew(MenuAnchor, SMenuAnchor)
+ .OnGetMenuContent(this, &SPatternSelector::CreatePatternList)
+ .Placement(EMenuPlacement::MenuPlacement_ComboBox)
+ [
+ SAssignNew(SelectPatternName, STextBlock)
+ ]
+ ];
+
+ FMidiSequencer::Get().OnNewPattern.AddRaw(this, &SPatternSelector::OnNewPattern);
+ FMidiSequencer::Get().OnDeletePattern.AddRaw(this, &SPatternSelector::OnDeletePattern);
+
+ for (FPattern* MidiPattern : FMidiSequencer::Get().GetPattern(EPatternType::Midi))
+ {
+ OnNewPattern(MidiPattern);
+ }
+}
+
+FReply SPatternSelector::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
+ {
+ MenuAnchor->SetIsOpen(true);
+ }
+ return SCompoundWidget::OnMouseButtonDown(MyGeometry, MouseEvent);
+}
+
+void SPatternSelector::OnPatternSelected(FPattern* Pattern)
+{
+ SelectPatternName->SetText(FText::FromString(Pattern->Name));
+ MenuAnchor->SetIsOpen(false);
+ FPatternSelector::Get().SelectPattern(Pattern);
+}
+
+void SPatternSelector::OnPatternDeselected(FPattern* Pattern)
+{
+ SelectPatternName->SetText(FText::FromString("无"));
+}
+
+void SPatternSelector::OnNewPattern(FPattern* Pattern)
+{
+ const TSharedRef PatternThumbnail = SNew(SAutoPatternThumbnail, Pattern);
+ PatternThumbnail->OnPatternClicked.AddRaw(this, &SPatternSelector::OnPatternSelected);
+ PatternList->AddSlot()
+ .HAlign(HAlign_Fill)
+ [
+ PatternThumbnail
+ ];
+}
+
+void SPatternSelector::OnDeletePattern(FPattern* Pattern)
+{
+ const TSharedPtr& ScrollPanel = PatternList->GetScrollPanel();
+ FChildren* Children = ScrollPanel->GetChildren();
+ for (int32 i = 0; i < Children->Num(); ++i)
+ {
+ TSharedRef Child = Children->GetChildAt(i);
+ TSharedRef ThumbnailWidget = StaticCastSharedRef(Child);
+ if (ThumbnailWidget->GetPattern() == Pattern)
+ {
+ PatternList->RemoveSlot(Child);
+ break;
+ }
+ }
+}
+
+TSharedRef SPatternSelector::CreatePatternList()
+{
+ return PatternList.ToSharedRef();
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/PatternThumbnail/SPatternSelector.h b/Source/Arona/UI/Widget/PatternThumbnail/SPatternSelector.h
new file mode 100644
index 0000000..e35f72a
--- /dev/null
+++ b/Source/Arona/UI/Widget/PatternThumbnail/SPatternSelector.h
@@ -0,0 +1,45 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+
+class STextBlock;
+class SAutoPatternThumbnail;
+class SPatternThumbnail;
+class SMidiPatternThumbnail;
+class SScrollBox;
+class SMenuAnchor;
+class FPattern;
+/**
+ *
+ */
+class ARONA_API SPatternSelector : public SCompoundWidget
+{
+public:
+ SLATE_BEGIN_ARGS(SPatternSelector)
+ {
+ }
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs);
+
+ virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+private:
+ void OnPatternSelected(FPattern* Pattern);
+ void OnPatternDeselected(FPattern* Pattern);
+
+ void OnNewPattern(FPattern* Pattern);
+ void OnDeletePattern(FPattern* Pattern);
+
+ TSharedRef CreatePatternList();
+
+ TSharedPtr MenuAnchor;
+ TSharedPtr PatternList;
+ TSharedPtr SelectPatternName;
+
+ TSharedPtr Thumbnail;
+};
diff --git a/Source/Arona/UI/Widget/PatternThumbnail/SPatternThumbnail.cpp b/Source/Arona/UI/Widget/PatternThumbnail/SPatternThumbnail.cpp
new file mode 100644
index 0000000..cd31a34
--- /dev/null
+++ b/Source/Arona/UI/Widget/PatternThumbnail/SPatternThumbnail.cpp
@@ -0,0 +1,93 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SPatternThumbnail.h"
+
+#include "SInvalidationPanel.h"
+#include "SlateOptMacros.h"
+#include "SMidiPatternThumbnail.h"
+#include "SSamplePatternThumbnail.h"
+#include "STextBlock.h"
+#include "Pattern/Pattern.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SNullPatternThumbnail::Construct(const FArguments& InArgs, FText InText)
+{
+ ChildSlot
+ [
+ SNew(STextBlock)
+ .Justification(ETextJustify::Center)
+ .Text(InText)
+ ];
+}
+
+TSharedRef SNullPatternThumbnail::Create(FText InText)
+{
+ return SNew(SNullPatternThumbnail, InText);
+}
+
+void SAutoPatternThumbnail::Construct(const FArguments& InArgs, FPattern* InPattern)
+{
+ SetPattern(InPattern);
+}
+
+void SAutoPatternThumbnail::SetPattern(FPattern* InPattern)
+{
+ Pattern = InPattern;
+ ChildSlot.DetachWidget();
+ Thumbnail = CreateThumbnail(InPattern);
+ ChildSlot
+ [
+ SNew(SInvalidationPanel)
+ [
+ Thumbnail.ToSharedRef()
+ ]
+ ];
+ Thumbnail->Redraw();
+}
+
+FReply SAutoPatternThumbnail::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && Thumbnail.IsValid())
+ {
+ if (Thumbnail->GetPattern())
+ {
+ OnPatternClicked.Broadcast(Thumbnail->GetPattern());
+ }
+ }
+ return FReply::Unhandled();
+}
+
+FVector2D SAutoPatternThumbnail::ComputeDesiredSize(float LayoutScaleMultiplier) const
+{
+ return FVector2D(0, 36) * LayoutScaleMultiplier;
+}
+
+TSharedPtr SAutoPatternThumbnail::CreateThumbnail(FPattern* InPattern)
+{
+ TSharedPtr Out;
+ if (!InPattern)
+ {
+ Out = SNullPatternThumbnail::Create(FText::FromString(TEXT("Null Pattern")));
+ }
+ else
+ {
+ switch (Pattern->Type)
+ {
+ case EPatternType::Midi:
+ SAssignNew(Out, SMidiPatternThumbnail);
+ break;
+ case EPatternType::Automation:
+ break;
+ case EPatternType::Sample:
+ SAssignNew(Out, SSamplePatternThumbnail, static_cast(InPattern)->GetSampler());
+ break;
+ default: ;
+ }
+ }
+ Out->SetPattern(InPattern);
+ return Out;
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/PatternThumbnail/SPatternThumbnail.h b/Source/Arona/UI/Widget/PatternThumbnail/SPatternThumbnail.h
new file mode 100644
index 0000000..d505f44
--- /dev/null
+++ b/Source/Arona/UI/Widget/PatternThumbnail/SPatternThumbnail.h
@@ -0,0 +1,68 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "Singleton/MidiSequencer.h"
+
+class FMidiMessageSequence;
+class FPluginHost;
+class FPattern;
+
+class ARONA_API SPatternThumbnail : public SCompoundWidget
+{
+public:
+ void SetPattern(FPattern* InPattern) { OnPatternChanged(CurrentPattern, InPattern); CurrentPattern = InPattern; }
+ FPattern* GetPattern() const { return CurrentPattern; }
+ virtual void Redraw() {}
+
+ TRange MidiTickRange;
+protected:
+ virtual void OnPatternChanged(FPattern* OldPattern, FPattern* NewPattern) {}
+private:
+ FPattern* CurrentPattern = nullptr;
+};
+
+class ARONA_API SNullPatternThumbnail : public SPatternThumbnail
+{
+public:
+ SLATE_BEGIN_ARGS(SNullPatternThumbnail)
+ {
+ }
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FText InText);
+
+ static TSharedRef Create(FText InText);
+};
+
+/**
+ *
+ */
+class ARONA_API SAutoPatternThumbnail : public SCompoundWidget
+{
+public:
+ SLATE_BEGIN_ARGS(SAutoPatternThumbnail)
+ {
+ }
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FPattern* InPattern);
+
+ void SetPattern(FPattern* InPattern);
+ FPattern* GetPattern() const { return Pattern; }
+
+ virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override;
+ FPatternDelegate OnPatternClicked;
+private:
+ TSharedPtr CreateThumbnail(FPattern* InPattern);
+
+ TSharedPtr Thumbnail;
+ FPattern* Pattern = nullptr;
+};
diff --git a/Source/Arona/UI/Widget/PatternThumbnail/SSamplePatternThumbnail.cpp b/Source/Arona/UI/Widget/PatternThumbnail/SSamplePatternThumbnail.cpp
new file mode 100644
index 0000000..ca59cbc
--- /dev/null
+++ b/Source/Arona/UI/Widget/PatternThumbnail/SSamplePatternThumbnail.cpp
@@ -0,0 +1,39 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SSamplePatternThumbnail.h"
+
+#include "Async.h"
+#include "SlateApplication.h"
+#include "SlateOptMacros.h"
+#include "ExecutionTime.h"
+#include "Pattern/SamplePatternInstance.h"
+#include "PluginHost/Sampler.h"
+#include "UI/Widget/SUpdatableImage.h"
+#include "UI/Widget/Thumbnail.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+TArray FSampleWaveformHandle::GetWaveform(int32 SizeX) const
+{
+
+ const FSampler* Sampler = SampleInstance->GetInstanceOwner()->GetSampler();
+ TArray> Copy = Sampler->GetSampleBuffer(); // 拷贝以防在渲染时被修改
+ uint32 Count = Sampler->GetFrameCount();
+ TRange Range = SampleInstance->GetRange();
+ return Thumbnail::GenerateWaveformData(SizeX, Copy, Count, Range);
+}
+
+void SSamplePatternThumbnail::Construct(const FArguments& InArgs, FSampler* InSampler)
+{
+ ChildSlot
+ [
+
+ ];
+}
+
+void SSamplePatternThumbnail::Redraw()
+{
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/PatternThumbnail/SSamplePatternThumbnail.h b/Source/Arona/UI/Widget/PatternThumbnail/SSamplePatternThumbnail.h
new file mode 100644
index 0000000..92a14df
--- /dev/null
+++ b/Source/Arona/UI/Widget/PatternThumbnail/SSamplePatternThumbnail.h
@@ -0,0 +1,37 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "SPatternThumbnail.h"
+#include "Render/UpdatableTexture.h"
+#include "UI/Widget/WaveformViewer.h"
+
+class FSampler;
+
+
+class FSampleWaveformHandle : public IWaveformHandle
+{
+public:
+ FSamplePatternInstance* SampleInstance = nullptr;
+ virtual TArray GetWaveform(int32 SizeX) const override;
+};
+
+/**
+ *
+ */
+class ARONA_API SSamplePatternThumbnail : public SPatternThumbnail
+{
+public:
+ SLATE_BEGIN_ARGS(SSamplePatternThumbnail)
+ {}
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FSampler* InSampler);
+
+ virtual void Redraw() override;
+private:
+ FSampleWaveformHandle* WaveformHandle = nullptr;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool.cpp b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool.cpp
new file mode 100644
index 0000000..4e6fad8
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool.cpp
@@ -0,0 +1,55 @@
+#include "PianoRollEditTool.h"
+
+#include "PluginHost/PluginHost.h"
+
+void FPianoRollEditTool::OnActive(FPianoRollEdit& Edit)
+{
+ PluginHost = Edit.GetPluginHost();
+}
+
+void FPianoRollEditTool::Clear(FPianoRollEdit& Edit)
+{
+ PluginHost = nullptr;
+}
+
+void FPianoRollEditTool::PlaySelected(FPianoRollEdit& Edit)
+{
+ if (!PluginHost)
+ return;
+
+ TArray Notes;
+ for (const FMidiMessageSequence::MidiEventHolder* Selected : Edit.Selector.GetSelectedMidiMessages())
+ {
+ if (!Selected->noteOffObject)
+ continue;
+ if (Notes.Contains(Selected->message.getNoteNumber()))
+ continue;
+
+ FMidiMessage NoteOn = Selected->message;
+ FMidiMessage NoteOff = Selected->noteOffObject->message;
+ Notes.Add(NoteOn.getNoteNumber());
+
+ PluginHost->IncomingMidi.addEvent(NoteOn, 0);
+ PluginHost->IncomingMidi.addEvent(NoteOff, 0);
+ }
+}
+
+void FPianoRollEditTool::StopSelected(FPianoRollEdit& Edit)
+{
+ if (!PluginHost)
+ return;
+
+ TArray Notes;
+ for (const FMidiMessageSequence::MidiEventHolder* Selected : Edit.Selector.GetSelectedMidiMessages())
+ {
+ if (!Selected->noteOffObject)
+ continue;
+ if (Notes.Contains(Selected->message.getNoteNumber()))
+ continue;
+
+ FMidiMessage NoteOff = Selected->noteOffObject->message;
+ Notes.Add(Selected->message.getNoteNumber());
+
+ PluginHost->IncomingMidi.addEvent(NoteOff, 0);
+ }
+}
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool.h b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool.h
new file mode 100644
index 0000000..f1a32ed
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "Reply.h"
+#include "WidgetStyle.h"
+#include "UI/Widget/PianoRoll/PianoRollPanel/PianoRollEdit.h"
+
+class FPianoRollEditTool
+{
+public:
+ FPianoRollEditTool(EPianoRollToolType InToolType) : PluginHost(nullptr), ToolType(InToolType)
+ {
+ }
+
+ virtual ~FPianoRollEditTool() = default;
+
+ virtual void OnActive(FPianoRollEdit& Edit);
+ virtual void Clear(FPianoRollEdit& Edit);
+
+ virtual void OnMouseButtonDown(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { }
+ virtual void OnMouseButtonUp(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { }
+ virtual void OnMouseMove(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { }
+
+ virtual void OnBeginDrag(FPianoRollEdit& Edit, FVector2f InMouseStartPos) { }
+ virtual void OnEndDrag(FPianoRollEdit& Edit, FVector2f InMouseEndPos) { }
+
+ virtual int32 OnPaint(const FPianoRollEdit& Edit, const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { return LayerId; }
+
+ EPianoRollToolType GetToolType() const { return ToolType; }
+ FPluginHost* GetPluginHost() const { return PluginHost; }
+protected:
+ void PlaySelected(FPianoRollEdit& Edit);
+ void StopSelected(FPianoRollEdit& Edit);
+private:
+ FPluginHost* PluginHost;
+ EPianoRollToolType ToolType;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_DragView.cpp b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_DragView.cpp
new file mode 100644
index 0000000..9e92248
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_DragView.cpp
@@ -0,0 +1,44 @@
+#include "PianoRollEditTool_DragView.h"
+
+#include "SlateApplication.h"
+#include "UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.h"
+
+void FPianoRollEditTool_DragView::OnActive(FPianoRollEdit& Edit)
+{
+ FPianoRollEditTool::OnActive(Edit);
+ const TSharedPtr Panel = Edit.PianoRollPanel.Pin();
+ OriginalRange = Panel->TimeRange;
+ OriginalMousePos = FSlateApplication::Get().GetCursorPos();
+}
+
+void FPianoRollEditTool_DragView::OnMouseButtonDown(FPianoRollEdit& Edit, const FGeometry& MyGeometry,
+ const FPointerEvent& MouseEvent)
+{
+ OriginalMousePos = MouseEvent.GetScreenSpacePosition();
+ const TSharedPtr Panel = Edit.PianoRollPanel.Pin();
+ OriginalRange = Panel->TimeRange;
+}
+
+void FPianoRollEditTool_DragView::OnMouseMove(FPianoRollEdit& Edit, const FGeometry& MyGeometry,
+ const FPointerEvent& MouseEvent)
+{
+ if (!MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
+ return;
+
+ const FVector2f MouseCurrentPos = MouseEvent.GetScreenSpacePosition();
+ TSharedPtr Panel = Edit.PianoRollPanel.Pin();
+ const FVector2f Delta = MouseCurrentPos - OriginalMousePos;
+ const double TickDelta = Delta.X / Panel->FrameToPixel / MyGeometry.Scale;
+
+ const AudioFrame Lower = FMath::Max(0, OriginalRange.GetLowerBoundValue() - TickDelta);
+ const AudioFrame Upper = FMath::Max(OriginalRange.Size(), OriginalRange.GetUpperBoundValue() - TickDelta);
+ Panel->OnTargetRangeChanged.ExecuteIfBound(TRange(Lower, Upper));
+ Panel->OnYRequestUpdate.ExecuteIfBound(-MouseEvent.GetCursorDelta().Y / MyGeometry.Scale);
+}
+
+void FPianoRollEditTool_DragView::OnBeginDrag(FPianoRollEdit& Edit, FVector2f InMouseStartPos)
+{
+ OriginalMousePos = FSlateApplication::Get().GetCursorPos();
+ const TSharedPtr Panel = Edit.PianoRollPanel.Pin();
+ OriginalRange = Panel->TimeRange;
+}
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_DragView.h b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_DragView.h
new file mode 100644
index 0000000..a2ec4a5
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_DragView.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "PianoRollEditTool.h"
+
+class FPianoRollEditTool_DragView : public FPianoRollEditTool
+{
+public:
+ FPianoRollEditTool_DragView() : FPianoRollEditTool(EPianoRollToolType::DragView)
+ {
+ }
+
+ virtual void OnActive(FPianoRollEdit& Edit) override;
+ virtual void OnMouseButtonDown(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual void OnMouseMove(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual void OnBeginDrag(FPianoRollEdit& Edit, FVector2f InMouseStartPos) override;
+private:
+ TRange OriginalRange;
+ FVector2f OriginalMousePos;
+ float OriginalYOffset = 0;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Select.cpp b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Select.cpp
new file mode 100644
index 0000000..8796ba9
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Select.cpp
@@ -0,0 +1,104 @@
+#include "PianoRollEditTool_Select.h"
+
+#include "SlateApplication.h"
+#include "PluginHost/PluginHost.h"
+#include "UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.h"
+
+void FPianoRollEditTool_Select::Clear(FPianoRollEdit& Edit)
+{
+ FPianoRollEditTool::Clear(Edit);
+ RectSelecting = false;
+}
+
+void FPianoRollEditTool_Select::OnMouseButtonDown(FPianoRollEdit& Edit, const FGeometry& MyGeometry,
+ const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
+ RectSelecting = true;
+}
+
+void FPianoRollEditTool_Select::OnMouseButtonUp(FPianoRollEdit& Edit, const FGeometry& MyGeometry,
+ const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
+ RectSelecting = false;
+}
+
+void FPianoRollEditTool_Select::OnMouseMove(FPianoRollEdit& Edit, const FGeometry& MyGeometry,
+ const FPointerEvent& MouseEvent)
+{
+ MouseCurrentPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
+}
+
+void FPianoRollEditTool_Select::OnEndDrag(FPianoRollEdit& Edit, FVector2f InMouseEndPos)
+{
+ Edit.Selector.UnSelect();
+
+ const TSharedPtr Panel = Edit.PianoRollPanel.Pin();
+ const FVector2f& MouseDownPos = Edit.GetMouseDownPos();
+
+ TArray InRectMidiMessages;
+ const int MouseDownNote = FMath::Abs(Panel->HeightToNoteNumber(MouseDownPos.Y));
+ const int MouseUpNote = FMath::Abs(Panel->HeightToNoteNumber(InMouseEndPos.Y));
+
+ const TRange NoteRange(MouseUpNote, MouseDownNote);
+ const TRange MouseMidiTickRange(Panel->PixelToFrame(MouseDownPos.X), Panel->PixelToFrame(InMouseEndPos.X));
+
+ FMidiMessageSequence* MidiEventHolders = Edit.GetMidiMessageSequence();
+ for (FMidiMessageSequence::MidiEventHolder* MidiMessage : *MidiEventHolders)
+ {
+ if (!MidiMessage->message.isNoteOn())
+ continue;
+
+ // 如果MidiMessage的时间戳大于选择框的结束时间,那么就不需要再遍历了
+ if (MidiMessage->message.getTimeStamp() > MouseMidiTickRange.GetUpperBoundValue())
+ break;
+
+ const double NoteOnTime = MidiMessage->message.getTimeStamp();
+ const double Duration = MidiMessage->getDuration();
+
+ if (!MouseMidiTickRange.Contains(NoteOnTime) && !MouseMidiTickRange.Contains(NoteOnTime + Duration))
+ continue;
+
+ const int NoteNumber = MidiMessage->message.getNoteNumber();
+ if (!NoteRange.Contains(NoteNumber))
+ continue;
+
+ InRectMidiMessages.Add(MidiMessage);
+ }
+
+ Edit.Selector.SelectMidiMessage(InRectMidiMessages);
+ PlaySelected(Edit);
+}
+
+int32 FPianoRollEditTool_Select::OnPaint(const FPianoRollEdit& Edit, const FPaintArgs& Args, const FGeometry& AllottedGeometry,
+ const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
+ const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
+{
+ if (!RectSelecting)
+ return LayerId;
+ // 绘制选择框
+ const FVector2f& MouseDownPos = Edit.GetMouseDownPos();
+ const FVector2f RectStart = FVector2f(MouseDownPos.X, MouseDownPos.Y);
+ const FVector2f RectEnd = FVector2f(MouseCurrentPos.X, MouseCurrentPos.Y);
+
+ // Draw Line
+ TArray Points;
+ Points.Add(RectStart);
+ Points.Add(FVector2f(RectEnd.X, RectStart.Y));
+ Points.Add(RectEnd);
+ Points.Add(FVector2f(RectStart.X, RectEnd.Y));
+ Points.Add(RectStart);
+ FSlateDrawElement::MakeLines(
+ OutDrawElements,
+ ++LayerId,
+ AllottedGeometry.ToPaintGeometry(),
+ Points,
+ ESlateDrawEffect::None,
+ FLinearColor::Red,
+ true,
+ 1
+ );
+
+ return LayerId;
+}
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Select.h b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Select.h
new file mode 100644
index 0000000..28e7b75
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Select.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "PianoRollEditTool.h"
+
+class FPianoRollEditTool_Select : public FPianoRollEditTool
+{
+public:
+ FPianoRollEditTool_Select() : FPianoRollEditTool(EPianoRollToolType::Select)
+ {
+ }
+
+ virtual void Clear(FPianoRollEdit& Edit) override;
+ virtual void OnMouseButtonDown(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual void OnMouseButtonUp(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual void OnMouseMove(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual void OnEndDrag(FPianoRollEdit& Edit, FVector2f InMouseEndPos) override;
+
+ virtual int32 OnPaint(const FPianoRollEdit& Edit, const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
+private:
+ bool RectSelecting = false;
+ FVector2f MouseCurrentPos;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Write.cpp b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Write.cpp
new file mode 100644
index 0000000..8b19f0f
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Write.cpp
@@ -0,0 +1,184 @@
+#include "PianoRollEditTool_Write.h"
+
+#include "Singleton/MidiSequencer.h"
+#include "PluginHost/PluginHost.h"
+#include "UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.h"
+
+FPianoRollEditTool_Write::FPianoRollEditTool_Write(): FPianoRollEditTool(EPianoRollToolType::Write), Channel(1),
+ Velocity(1), NoteLength(FMidiSequencer::Get().GetBeat())
+{
+ TempSelector.OnMidiMessageSelected.AddRaw(this, &FPianoRollEditTool_Write::OnMidiMessageSelected);
+ TempSelector.OnMidiMessageUnSelected.AddRaw(this, &FPianoRollEditTool_Write::OnMidiMessageUnSelected);
+}
+
+void FPianoRollEditTool_Write::OnActive(FPianoRollEdit& Edit)
+{
+ FPianoRollEditTool::OnActive(Edit);
+ Edit.Selector.OnMidiMessageSelected.AddRaw(this, &FPianoRollEditTool_Write::OnMidiMessageSelected);
+ Edit.Selector.OnMidiMessageUnSelected.AddRaw(this, &FPianoRollEditTool_Write::OnMidiMessageUnSelected);
+}
+
+void FPianoRollEditTool_Write::Clear(FPianoRollEdit& Edit)
+{
+ FPianoRollEditTool::Clear(Edit);
+ HasDeleteNote = false;
+ TempSelector.UnSelect();
+
+ Edit.Selector.OnMidiMessageSelected.RemoveAll(this);
+ Edit.Selector.OnMidiMessageUnSelected.RemoveAll(this);
+}
+
+void FPianoRollEditTool_Write::OnMouseButtonDown(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ HasDeleteNote = false;
+ if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
+ {
+ LeftMouseButton(Edit);
+ }
+
+ if (MouseEvent.GetEffectingButton() == EKeys::RightMouseButton)
+ {
+ RightMouseButton(Edit);
+ }
+}
+
+void FPianoRollEditTool_Write::OnMouseButtonUp(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && !HasDeleteNote)
+ Edit.Selector.UnSelect();
+ TempSelector.UnSelect();
+}
+
+void FPianoRollEditTool_Write::OnMouseMove(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ const FGeometry& TickSpaceGeometry = MyGeometry;
+ const auto& CursorPos = MouseEvent.GetScreenSpacePosition();
+ const auto& LocalPos = TickSpaceGeometry.AbsoluteToLocal(CursorPos);
+ const TSharedPtr Panel = Edit.PianoRollPanel.Pin();
+
+ if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
+ {
+ const int MouseNote = Panel->HeightToNoteNumber(LocalPos.Y);
+ const AudioFrame& NewFrame = Panel->PixelToFrame(LocalPos.X);
+ UpdateTempSelector(Edit, MouseNote, NewFrame.Ticks());
+ UpdateSelector(Edit, MouseNote, NewFrame.Ticks());
+ }
+
+ if (MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
+ {
+ RightMouseButton(Edit);
+ }
+}
+
+void FPianoRollEditTool_Write::OnMidiMessageSelected(FMidiMessageSequence::MidiEventHolder* MidiEventHolder)
+{
+ PlayNote(MidiEventHolder->message.getNoteNumber());
+}
+
+void FPianoRollEditTool_Write::OnMidiMessageUnSelected(FMidiMessageSequence::MidiEventHolder* MidiEventHolder)
+{
+ StopNote(MidiEventHolder->message.getNoteNumber());
+}
+
+void FPianoRollEditTool_Write::PlayNote(int32 Note)
+{
+ if (GetPluginHost())
+ GetPluginHost()->IncomingMidi.addEvent(FMidiMessage::noteOn(Channel, Note, Velocity));
+}
+
+void FPianoRollEditTool_Write::StopNote(int32 Note)
+{
+ if (GetPluginHost())
+ GetPluginHost()->IncomingMidi.addEvent(FMidiMessage::noteOff(Channel, Note, Velocity));
+}
+
+void FPianoRollEditTool_Write::LeftMouseButton(FPianoRollEdit& Edit)
+{
+ FPianoRollSelector& Selector = Edit.Selector;
+ const MidiTick SnapMidiTimestamp = Edit.GetSnapFrame();
+
+ if (const FNoteSelectData& SelectedNote = Edit.GetMidiMessageUnderMouse())
+ {
+ FMidiMessageSequence::MidiEventHolder* MidiEventHolder = SelectedNote.MidiMessage;
+ const int BasePitch = MidiEventHolder->message.getNoteNumber();
+ const double MidiTimestampDelta = SelectedNote.MidiTimestampOffset;
+ const double BaseMidiTimestamp = MidiEventHolder->message.getTimeStamp();
+ Channel = MidiEventHolder->message.getChannel();
+ Velocity = MidiEventHolder->message.getFloatVelocity();
+ NoteLength = MidiEventHolder->noteOffObject ? MidiEventHolder->noteOffObject->message.getTimeStamp() - BaseMidiTimestamp : 0;
+
+ if (Selector.IsSelected(MidiEventHolder))
+ {
+ Selector.BeginDrag(BasePitch, MidiTimestampDelta, SnapMidiTimestamp, BaseMidiTimestamp);
+ Selector.ResetAnchorPoint();
+ }
+ else
+ {
+ Selector.UnSelect();
+ TempSelector.UnSelect();
+ TempSelector.AddMidiMessage(MidiEventHolder);
+ TempSelector.BeginDrag(BasePitch, MidiTimestampDelta, SnapMidiTimestamp, BaseMidiTimestamp);
+ TempSelector.ResetAnchorPoint();
+ }
+ return;
+ }
+
+ Selector.UnSelect();
+
+ const int32 NoteNumberUnderMouse = Edit.GetNoteNumberUnderMouse();
+ const MidiTick MidiTickUnderMouse = Edit.GetAudioFrameUnderMouse();
+ const MidiTick TimestampDelta = MidiTickUnderMouse % SnapMidiTimestamp;
+ const MidiTick SnapMidiTick = MidiTickUnderMouse - TimestampDelta;
+
+ const FMidiMessage& NoteOn = FMidiMessage::noteOn(Channel, NoteNumberUnderMouse, Velocity);
+ FMidiMessageSequence::MidiEventHolder* MidiEventHolder = Edit.GetMidiMessageSequence()->addEvent(NoteOn, SnapMidiTick);
+ if (NoteLength > 0)
+ MidiEventHolder->noteOffObject = Edit.GetMidiMessageSequence()->addEvent(FMidiMessage::noteOff(Channel, NoteNumberUnderMouse, Velocity), SnapMidiTick + NoteLength);
+}
+
+void FPianoRollEditTool_Write::RightMouseButton(FPianoRollEdit& Edit)
+{
+ if (const FNoteSelectData& SelectedNote = Edit.GetMidiMessageUnderMouse())
+ {
+ Edit.Selector.UnSelect(SelectedNote.MidiMessage);
+ Edit.SetModified(true);
+ FMidiMessageSequence* Sequence = Edit.GetMidiMessageSequence();
+ const int NoteIndex = Sequence->getIndexOf(SelectedNote.MidiMessage);
+ Sequence->deleteEvent(NoteIndex, true);
+ HasDeleteNote = true;
+ }
+}
+
+void FPianoRollEditTool_Write::UpdateTempSelector(FPianoRollEdit& Edit, int32 NewNote, MidiTick NewTick)
+{
+ if (TempSelector.Num() == 0)
+ return;
+
+ const int32 LastNote = TempSelector.GetSelectedMidiMessages()[0]->message.getNoteNumber();
+ bool IsModify = TempSelector.SetPitch(NewNote);
+ if (IsModify)
+ {
+ StopNote(LastNote);
+ PlayNote(NewNote);
+ }
+
+ IsModify |= TempSelector.SetMidiTimestamp(NewTick);
+ if (IsModify)
+ {
+ Edit.SetModified(true);
+ }
+}
+
+void FPianoRollEditTool_Write::UpdateSelector(FPianoRollEdit& Edit, int32 NewNote, MidiTick NewTick)
+{
+ if (Edit.Selector.Num() == 0)
+ return;
+
+ bool IsModify = Edit.Selector.SetPitch(NewNote);
+ IsModify |= Edit.Selector.SetMidiTimestamp(NewTick);
+
+ if (IsModify)
+ {
+ Edit.SetModified(true);
+ }
+}
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Write.h b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Write.h
new file mode 100644
index 0000000..44c0e4c
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/EditTool/PianoRollEditTool_Write.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "PianoRollEditTool.h"
+
+class FPianoRollEditTool_Write : public FPianoRollEditTool
+{
+public:
+ FPianoRollEditTool_Write();
+
+ virtual void OnActive(FPianoRollEdit& Edit) override;
+ virtual void Clear(FPianoRollEdit& Edit) override;
+
+ virtual void OnMouseButtonDown(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual void OnMouseButtonUp(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual void OnMouseMove(FPianoRollEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+
+ int32 Channel;
+ float Velocity;
+ int64 NoteLength;
+private:
+ void OnMidiMessageSelected(FMidiMessageSequence::MidiEventHolder* MidiEventHolder);
+ void OnMidiMessageUnSelected(FMidiMessageSequence::MidiEventHolder* MidiEventHolder);
+
+ void PlayNote(int32 Note);
+ void StopNote(int32 Note);
+
+ void LeftMouseButton(FPianoRollEdit& Edit);
+ void RightMouseButton(FPianoRollEdit& Edit);
+
+ void UpdateTempSelector(FPianoRollEdit& Edit, int32 NewNote, MidiTick NewTick);
+ void UpdateSelector(FPianoRollEdit& Edit, int32 NewNote, MidiTick NewTick);
+
+ bool HasDeleteNote = false;
+
+ FPianoRollSelector TempSelector;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollEdit.cpp b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollEdit.cpp
new file mode 100644
index 0000000..50e69c4
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollEdit.cpp
@@ -0,0 +1,259 @@
+#include "PianoRollEdit.h"
+
+#include "SlateApplication.h"
+#include "SPianoRollPanel.h"
+#include "Pattern/MidiPattern.h"
+#include "Singleton/MidiSequencer.h"
+#include "EditTool/PianoRollEditTool.h"
+#include "EditTool/PianoRollEditTool_DragView.h"
+#include "EditTool/PianoRollEditTool_Select.h"
+#include "EditTool/PianoRollEditTool_Write.h"
+
+FPianoRollEdit::FPianoRollEdit(TSharedRef InPianoRollPanel)
+{
+ PianoRollPanel = InPianoRollPanel;
+
+ EditToolMap.Add(EPianoRollToolType::Write, new FPianoRollEditTool_Write());
+ EditToolMap.Add(EPianoRollToolType::Select, new FPianoRollEditTool_Select());
+ EditToolMap.Add(EPianoRollToolType::DragView, new FPianoRollEditTool_DragView());
+
+
+ ToolKeyMap.Add(EPianoRollToolType::Select, {EKeys::LeftControl, EKeys::LeftMouseButton});
+ ToolKeyMap.Add(EPianoRollToolType::DragView, {EKeys::LeftShift, EKeys::RightMouseButton});
+
+
+ CurrentEditTool = EditToolMap[EPianoRollToolType::Write];
+ CurrentEditTool->OnActive(*this);
+ TempTool = nullptr;
+}
+
+FPianoRollEdit::~FPianoRollEdit()
+{
+ for (const auto& Tuple : EditToolMap)
+ {
+ delete Tuple.Value;
+ }
+ EditToolMap.Empty();
+}
+
+FNoteSelectData FPianoRollEdit::GetMidiMessageByPos(FVector2D Pos) const
+{
+ const TSharedPtr Panel = PianoRollPanel.Pin();
+ FNoteSelectData OutData;
+
+ const int Note = Panel->HeightToNoteNumber(Pos.Y);
+ const float& FrameToPixel = Panel->FrameToPixel;
+ const TRange& FrameRange = Panel->TimeRange;
+ FMidiMessageSequence* MidiEventHolders = Panel->MidiMessageSequence;
+
+ // UE_LOG(LogTemp, Log, TEXT("Find Note: %s"), *FMidiMessage::getMidiNoteName(Note, true, true, 3));
+ AudioFrame Time = Pos.X / FrameToPixel;
+ Time += FrameRange.GetLowerBoundValue();
+ const MidiTick Ticks = Time.Ticks();
+ for (FMidiMessageSequence::MidiEventHolder* Holder : *MidiEventHolders)
+ {
+ if (Holder->message.getNoteNumber() != Note)
+ continue;
+ MidiTick BeginMidiTick = FrameRange.GetLowerBoundValue().Ticks();
+ if (Holder->message.getTimeStamp() > BeginMidiTick)
+ break;
+ if (!Holder->message.isNoteOn())
+ continue;
+ if (Ticks < Holder->message.getTimeStamp())
+ continue;
+
+ const FMidiMessageSequence::MidiEventHolder* NoteOffHolder = Holder->noteOffObject;
+ if (NoteOffHolder && Ticks > NoteOffHolder->message.getTimeStamp())
+ continue;
+
+ OutData.MidiMessage = Holder;
+ OutData.MidiTimestampOffset = Ticks - (int64)Holder->message.getTimeStamp();
+ return OutData;
+ }
+
+ return OutData;
+}
+
+FNoteSelectData FPianoRollEdit::GetMidiMessageUnderMouse() const
+{
+ const TSharedPtr Panel = PianoRollPanel.Pin();
+ const FGeometry& TickSpaceGeometry = Panel->GetTickSpaceGeometry();
+ const auto& LocalPos = TickSpaceGeometry.AbsoluteToLocal(FSlateApplication::Get().GetCursorPos());
+ return GetMidiMessageByPos(LocalPos);
+}
+
+FReply FPianoRollEdit::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ MouseDownPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
+ TryEnableTempTool();
+
+ GetCurrentTool()->OnMouseButtonDown(*this, MyGeometry, MouseEvent);
+ UpdateModified();
+ return FReply::Handled();
+}
+
+FReply FPianoRollEdit::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ const FVector2f MouseUpLocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
+
+ // OnEndDrag需要在OnMouseUp之前调用,因为OnMouseUp可能会清除OnMouseDrag
+ if (OnMouseDrag)
+ {
+ OnMouseDrag = false;
+ GetCurrentTool()->OnEndDrag(*this, MouseUpLocalPos);
+ UpdateModified();
+ }
+
+ {
+ GetCurrentTool()->OnMouseButtonUp(*this, MyGeometry, MouseEvent);
+ UpdateModified();
+ }
+
+ TryEnableTempTool();
+
+ return FReply::Handled();
+}
+
+FReply FPianoRollEdit::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ const FGeometry& TickSpaceGeometry = MyGeometry;
+ const auto& CursorPos = MouseEvent.GetScreenSpacePosition();
+ const auto& LocalPos = TickSpaceGeometry.AbsoluteToLocal(CursorPos);
+ TSharedPtr Panel = PianoRollPanel.Pin();
+
+ if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton) && !OnMouseDrag)
+ {
+ OnMouseDrag = true;
+ GetCurrentTool()->OnBeginDrag(*this, LocalPos);
+ UpdateModified();
+ }
+
+ GetCurrentTool()->OnMouseMove(*this, MyGeometry, MouseEvent);
+ UpdateModified();
+ return FReply::Handled();
+}
+
+FReply FPianoRollEdit::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent)
+{
+ if (KeyEvent.IsRepeat())
+ return FReply::Handled();
+ PressedKeys.Add(KeyEvent.GetKey());
+ TryEnableTempTool();
+ return FReply::Handled();
+}
+
+FReply FPianoRollEdit::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent)
+{
+ if (KeyEvent.IsRepeat())
+ return FReply::Handled();
+ PressedKeys.Remove(KeyEvent.GetKey());
+ TryEnableTempTool();
+ return FReply::Handled();
+}
+
+int32 FPianoRollEdit::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry,
+ const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
+ const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
+{
+ return GetCurrentTool()->OnPaint(*this, Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
+}
+
+int32 FPianoRollEdit::GetNoteNumberByPos(float Height) const
+{
+ const TSharedPtr Panel = PianoRollPanel.Pin();
+ return Panel->HeightToNoteNumber(Height);
+}
+
+int32 FPianoRollEdit::GetNoteNumberUnderMouse() const
+{
+ const TSharedPtr Panel = PianoRollPanel.Pin();
+ const FGeometry& TickSpaceGeometry = Panel->GetTickSpaceGeometry();
+ const auto& LocalPos = TickSpaceGeometry.AbsoluteToLocal(FSlateApplication::Get().GetCursorPos());
+ return Panel->HeightToNoteNumber(LocalPos.Y);
+}
+
+AudioFrame FPianoRollEdit::GetAudioFrameByPos(float Width) const
+{
+ const TSharedPtr Panel = PianoRollPanel.Pin();
+ return Panel->PixelToFrame(Width);
+}
+
+AudioFrame FPianoRollEdit::GetAudioFrameUnderMouse() const
+{
+ const TSharedPtr Panel = PianoRollPanel.Pin();
+ const FGeometry& TickSpaceGeometry = Panel->GetTickSpaceGeometry();
+ const auto& LocalPos = TickSpaceGeometry.AbsoluteToLocal(FSlateApplication::Get().GetCursorPos());
+ return Panel->PixelToFrame(LocalPos.X);
+}
+
+AudioFrame FPianoRollEdit::GetSnapFrame() const
+{
+ return FMidiSequencer::Get().GetTicksPerQuarter();
+}
+
+FMidiMessageSequence* FPianoRollEdit::GetMidiMessageSequence() const
+{
+ return PianoRollPanel.Pin()->GetMidiMessageSequence();
+}
+
+FPluginHost* FPianoRollEdit::GetPluginHost() const
+{
+ FMidiMessageSequence* Sequence = GetMidiMessageSequence();
+ if (!Sequence)
+ return nullptr;
+ return Sequence->pattern->GetPluginHost(Sequence);
+}
+
+void FPianoRollEdit::SetTempTool(EPianoRollToolType InToolType)
+{
+ CurrentEditTool->Clear(*this);
+ TempTool = EditToolMap[InToolType];
+ TempTool->OnActive(*this);
+}
+
+void FPianoRollEdit::ClearTempTool()
+{
+ if (TempTool)
+ {
+ TempTool->Clear(*this);
+ TempTool = nullptr;
+ CurrentEditTool->OnActive(*this);
+ }
+}
+
+void FPianoRollEdit::UpdateModified()
+{
+ if (GetModified())
+ {
+ GetMidiMessageSequence()->sortAudioThread();
+ SetModified(false);
+ }
+}
+
+FPianoRollEditTool* FPianoRollEdit::TryEnableTempTool()
+{
+ const TSet& PressedMouseButtons = FSlateApplication::Get().GetPressedMouseButtons();
+ for (const auto& Tuple : ToolKeyMap)
+ {
+ const EPianoRollToolType PianoRollTool = Tuple.Key;
+ const TArray& Keys = Tuple.Value;
+ bool bAllPressed = true;
+ for (const FKey& ToolKey : Keys)
+ {
+ if (ToolKey.IsMouseButton())
+ bAllPressed = bAllPressed && PressedMouseButtons.Contains(ToolKey);
+ else
+ bAllPressed = bAllPressed && PressedKeys.Contains(ToolKey);
+ if (!bAllPressed)
+ break;
+ }
+ if (bAllPressed)
+ {
+ ClearTempTool();
+ SetTempTool(PianoRollTool);
+ return EditToolMap[PianoRollTool];
+ }
+ }
+ ClearTempTool();
+ return nullptr;
+}
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollEdit.h b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollEdit.h
new file mode 100644
index 0000000..59963d9
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollEdit.h
@@ -0,0 +1,86 @@
+#pragma once
+#include "CoreMinimal.h"
+#include "Events.h"
+#include "Geometry.h"
+#include "PaintArgs.h"
+#include "PianoRollSelector.h"
+#include "Reply.h"
+#include "WidgetStyle.h"
+#include "Midi/MidiMessageSequence.h"
+#include "Midi/MidiType.h"
+#include "Midi/Time/TimePos.h"
+class FPluginHost;
+class FPianoRollEditTool;
+class SPianoRollPanel;
+
+enum class EPianoRollToolType
+{
+ Select,
+ Write,
+ DragView,
+ Count
+};
+
+struct FNoteSelectData
+{
+ FMidiMessageSequence::MidiEventHolder* MidiMessage = nullptr;
+ double MidiTimestampOffset = 0;
+ operator bool() const
+ {
+ return MidiMessage != nullptr;
+ }
+};
+
+class FPianoRollEdit
+{
+public:
+ FPianoRollEdit(TSharedRef InPianoRollPanel);
+ ~FPianoRollEdit();
+
+ FNoteSelectData GetMidiMessageByPos(FVector2D Pos) const;
+ FNoteSelectData GetMidiMessageUnderMouse() const;
+
+ FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);
+ FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);
+ FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);
+ FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent);
+ FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent);
+ int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const;
+
+ int32 GetNoteNumberByPos(float Height) const;
+ int32 GetNoteNumberUnderMouse() const;
+ AudioFrame GetAudioFrameByPos(float Width) const;
+ AudioFrame GetAudioFrameUnderMouse() const;
+
+ bool IsNoteSelected(FMidiMessageSequence::MidiEventHolder* MidiMessage) const { return Selector.IsSelected(MidiMessage); }
+ bool IsMultiSelected() const { return Selector.Num() > 1; }
+ FVector2f GetMouseDownPos() const { return MouseDownPos; }
+ void SetModified(bool InHasModified) { HasModified = InHasModified; }
+ bool GetModified() const { return HasModified; }
+ bool IsMouseDragging() const { return OnMouseDrag; }
+ AudioFrame GetSnapFrame() const;
+ FMidiMessageSequence* GetMidiMessageSequence() const;
+ FPluginHost* GetPluginHost() const;
+
+ void SetTempTool(EPianoRollToolType InToolType);
+ void ClearTempTool();
+
+ FPianoRollSelector Selector;
+ TWeakPtr PianoRollPanel;
+protected:
+ bool OnMouseDrag = false;
+private:
+ void UpdateModified();
+ FPianoRollEditTool* TryEnableTempTool();
+
+ FVector2f MouseDownPos;
+ bool HasModified = false;
+
+ TArray PressedKeys;
+
+ FPianoRollEditTool* GetCurrentTool() const { return TempTool ? TempTool : CurrentEditTool; }
+ FPianoRollEditTool* TempTool = nullptr;
+ FPianoRollEditTool* CurrentEditTool = nullptr;
+ TMap EditToolMap;
+ TMap> ToolKeyMap;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollSelector.cpp b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollSelector.cpp
new file mode 100644
index 0000000..14a4dba
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollSelector.cpp
@@ -0,0 +1,111 @@
+#include "PianoRollSelector.h"
+
+void FPianoRollSelector::SelectMidiMessage(TArray InMidiMessages)
+{
+ UnSelect();
+ for (auto MidiMessage : InMidiMessages)
+ {
+ FData& D = SelectedMidiMessages.AddDefaulted_GetRef();
+ D.MidiMessage = MidiMessage;
+ D.OriginalPitch = MidiMessage->message.getNoteNumber();
+ D.OriginalMidiTimestamp = MidiMessage->message.getTimeStamp();
+
+ OnMidiMessageSelected.Broadcast(MidiMessage);
+ }
+}
+
+void FPianoRollSelector::AddMidiMessage(FMidiMessageSequence::MidiEventHolder* MidiMessage)
+{
+ if (SelectedMidiMessages.Contains(MidiMessage))
+ return;
+
+ FData& D = SelectedMidiMessages.AddDefaulted_GetRef();
+ D.MidiMessage = MidiMessage;
+ D.OriginalPitch = MidiMessage->message.getNoteNumber();
+ D.OriginalMidiTimestamp = MidiMessage->message.getTimeStamp();
+
+ OnMidiMessageSelected.Broadcast(MidiMessage);
+}
+
+void FPianoRollSelector::UnSelect()
+{
+ for (const auto& D : SelectedMidiMessages)
+ {
+ OnMidiMessageUnSelected.Broadcast(D.MidiMessage);
+ }
+ SelectedMidiMessages.Reset();
+}
+
+void FPianoRollSelector::UnSelect(FMidiMessageSequence::MidiEventHolder* MidiMessage)
+{
+ if (SelectedMidiMessages.RemoveAll([&MidiMessage](const FData& Element) { return Element == MidiMessage; }) != 0)
+ {
+ OnMidiMessageUnSelected.Broadcast(MidiMessage);
+ }
+}
+
+bool FPianoRollSelector::SetPitch(int Pitch)
+{
+ const int PitchDelta = Pitch - BasePitch;
+ for (const FData& D : SelectedMidiMessages)
+ {
+ const int NewNoteNumber = D.OriginalPitch + PitchDelta;
+ D.MidiMessage->message.setNoteNumber(NewNoteNumber);
+ if (D.MidiMessage->noteOffObject)
+ D.MidiMessage->noteOffObject->message.setNoteNumber(NewNoteNumber);
+ }
+
+ if (LastPitch != Pitch)
+ {
+ LastPitch = Pitch;
+ return true;
+ }
+ return false;
+}
+
+bool FPianoRollSelector::SetMidiTimestamp(MidiTick InMidiTick)
+{
+ MidiTick TimestampOffset = BaseMidiTimestamp - InMidiTick + MidiTimestampDelta; // 点击位置的MidiTick
+ TimestampOffset = FMath::GridSnap(TimestampOffset, SnapMidiTimestamp);
+
+ for (const FData& D : SelectedMidiMessages)
+ {
+ const double NewTimestamp = FMath::Max(0, D.OriginalMidiTimestamp - TimestampOffset);
+
+ const double Duration = D.MidiMessage->getDuration();
+ D.MidiMessage->message.setTimeStamp(NewTimestamp);
+ if (D.MidiMessage->noteOffObject)
+ D.MidiMessage->noteOffObject->message.setTimeStamp(NewTimestamp + Duration);
+ }
+
+ if (LastMidiTimestamp != TimestampOffset)
+ {
+ LastMidiTimestamp = TimestampOffset;
+ return true;
+ }
+ return false;
+}
+
+void FPianoRollSelector::ResetAnchorPoint()
+{
+ for (FData& D : SelectedMidiMessages)
+ {
+ D.OriginalPitch = D.MidiMessage->message.getNoteNumber();
+ D.OriginalMidiTimestamp = D.MidiMessage->message.getTimeStamp();
+ }
+}
+
+bool FPianoRollSelector::IsSelected(FMidiMessageSequence::MidiEventHolder* MidiMessage) const
+{
+ return SelectedMidiMessages.Contains(MidiMessage);
+}
+
+TArray FPianoRollSelector::GetSelectedMidiMessages() const
+{
+ TArray OutSelectedMidiMessages;
+ for (const FData& D : SelectedMidiMessages)
+ {
+ OutSelectedMidiMessages.Add(D.MidiMessage);
+ }
+ return OutSelectedMidiMessages;
+}
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollSelector.h b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollSelector.h
new file mode 100644
index 0000000..e133515
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/PianoRollSelector.h
@@ -0,0 +1,57 @@
+#pragma once
+#include "CoreMinimal.h"
+#include "Midi/MidiMessageSequence.h"
+#include "Midi/Time/TimePos.h"
+
+DECLARE_MULTICAST_DELEGATE_OneParam(FMidiMessageDelegate, FMidiMessageSequence::MidiEventHolder*)
+
+class FPianoRollSelector
+{
+ struct FData
+ {
+ FMidiMessageSequence::MidiEventHolder* MidiMessage;
+ int OriginalPitch;
+ double OriginalMidiTimestamp;
+
+ bool operator==(FMidiMessageSequence::MidiEventHolder* In) const
+ {
+ return MidiMessage == In;
+ }
+ };
+public:
+ void SelectMidiMessage(TArray InMidiMessages);
+ void AddMidiMessage(FMidiMessageSequence::MidiEventHolder* MidiMessage);
+ void UnSelect();
+ void UnSelect(FMidiMessageSequence::MidiEventHolder* MidiMessage);
+
+ void BeginDrag(int InBasePitch, MidiTick InMidiTimestampDelta, MidiTick InSnapMidiTimestamp, MidiTick InBaseMidiTimestamp)
+ {
+ BasePitch = InBasePitch;
+ MidiTimestampDelta = InMidiTimestampDelta;
+ SnapMidiTimestamp = InSnapMidiTimestamp;
+ BaseMidiTimestamp = InBaseMidiTimestamp;
+
+ LastPitch = InBasePitch;
+ LastMidiTimestamp.Ticks = 0;
+ }
+ void ResetAnchorPoint();
+
+ bool SetPitch(int Pitch);
+ bool SetMidiTimestamp(MidiTick InMidiTick);
+ bool IsSelected(FMidiMessageSequence::MidiEventHolder* MidiMessage) const;
+
+ TArray GetSelectedMidiMessages() const;
+ int32 Num() const { return SelectedMidiMessages.Num(); }
+
+ FMidiMessageDelegate OnMidiMessageSelected;
+ FMidiMessageDelegate OnMidiMessageUnSelected;
+private:
+ TArray SelectedMidiMessages;
+ int32 BasePitch = 0;
+ MidiTick MidiTimestampDelta;
+ MidiTick BaseMidiTimestamp;
+ MidiTick SnapMidiTimestamp;
+
+ int32 LastPitch = 0;
+ MidiTick LastMidiTimestamp;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.cpp b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.cpp
new file mode 100644
index 0000000..268dc7c
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.cpp
@@ -0,0 +1,206 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SPianoRollPanel.h"
+
+#include "FontMeasure.h"
+#include "SImage.h"
+#include "SlateApplication.h"
+#include "SlateOptMacros.h"
+#include "SScaleBox.h"
+#include "Singleton/MidiSequencer.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SPianoRollPanel::Construct(const FArguments& InArgs, FMidiMessageSequence* InMidiMessageSequence)
+{
+ FontInfo = InArgs._FontInfo;
+ NoteImage = InArgs._NoteImage;
+ MidiMessageSequence = InMidiMessageSequence;
+
+ const double MidiDuration = FMath::Min(FMidiSequencer::Get().GetBar() * 2 ,MidiMessageSequence->getEndTime());
+ SequenceWidth = MidiDuration * FrameToPixel;
+ TimeRange = TRange(0, MidiDuration);
+ OnTargetRangeChanged = InArgs._OnTargetRangeChanged;
+ OnYRequestUpdate = InArgs._OnYRequestUpdate;
+ OnRequestHScroll = InArgs._OnRequestHScroll;
+
+ SpacingLineColor = InArgs._SpacingLineColor;
+ NoteColor = InArgs._NoteColor;
+ NoteSelectedColor = InArgs._NoteSelectedColor;
+ NoteTextColor = InArgs._NoteTextColor;
+ SpacingLineThickness = InArgs._SpacingLineThickness;
+ Clipping = EWidgetClipping::ClipToBounds;
+ PianoRollEdit = MakeShareable(new FPianoRollEdit(SharedThis(this)));
+}
+
+int32 SPianoRollPanel::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect,
+ FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle,
+ bool bParentEnabled) const
+{
+ const float RangeBegin = TimeRange.GetLowerBoundValue();
+ const float RangeEnd = TimeRange.GetUpperBoundValue();
+ if (FMath::IsNaN(RangeBegin) || FMath::IsNaN(RangeEnd))
+ return LayerId;
+
+ const auto& Size = AllottedGeometry.Size;
+
+ const FMidiSequencer& MidiSequencer = FMidiSequencer::Get();
+ const double CurrentMidiTick = MidiSequencer.FramePos.load().Ticks();
+ const int32 TicksPerQuarter = MidiSequencer.GetTicksPerQuarter();
+ int32 TicksPerBeat = MidiSequencer.GetBeat();
+ int32 TicksPerBar = MidiSequencer.GetBar();
+
+ ++LayerId;
+ // 绘制Note间隔线
+ for (int32 i = 0; i < FMidiMessage::MaxNoteNumber + 1; ++i)
+ {
+ TArray Points;
+ Points.Add(FVector2f(0, i * NoteHeight));
+ Points.Add(FVector2f(SequenceWidth, i * NoteHeight));
+ FSlateDrawElement::MakeLines(
+ OutDrawElements,
+ LayerId,
+ AllottedGeometry.ToPaintGeometry(),
+ Points,
+ ESlateDrawEffect::None,
+ SpacingLineColor,
+ true,
+ SpacingLineThickness
+ );
+ }
+
+ ++LayerId;
+ // 绘制节拍线
+ const float Delta = FMath::Fmod(RangeBegin, (float)TicksPerQuarter);
+ for (float i = RangeBegin - Delta; i < RangeEnd; i += TicksPerQuarter)
+ {
+ TArray Points;
+ Points.Add(FVector2f((i - RangeBegin) * FrameToPixel, 0));
+ Points.Add(FVector2f((i - RangeBegin) * FrameToPixel, Size.Y));
+ FSlateDrawElement::MakeLines(
+ OutDrawElements,
+ LayerId,
+ AllottedGeometry.ToPaintGeometry(),
+ Points,
+ ESlateDrawEffect::None,
+ SpacingLineColor,
+ true,
+ SpacingLineThickness
+ );
+ }
+
+ ++LayerId;
+ // 绘制Note
+ {
+ for (const auto& MidiMessage : *MidiMessageSequence)
+ {
+ if (!MidiMessage->message.isNoteOn())
+ continue;
+ double NoteOnTime = MidiMessage->message.getTimeStamp();
+ if (RangeEnd < NoteOnTime)
+ break;
+
+ float NoteOffRealTime;
+ if (MidiMessage->noteOffObject)
+ {
+ NoteOffRealTime = MidiMessage->noteOffObject->message.getTimeStamp();
+ if (RangeBegin > NoteOffRealTime)
+ continue;
+ NoteOffRealTime -= RangeBegin;
+ }
+ else
+ {
+ NoteOffRealTime = 0;
+ if (RangeBegin > NoteOnTime)
+ continue;
+ }
+
+ NoteOnTime -= RangeBegin;
+
+ const int NoteNumber = MidiMessage->message.getNoteNumber();
+ const float NoteOnX = NoteOnTime * FrameToPixel;
+ const float NoteOffX = NoteOffRealTime * FrameToPixel;
+ const float NoteY = (FMidiMessage::MaxNoteNumber - NoteNumber) * NoteHeight;
+ const float NoteWidth = NoteOffX - NoteOnX;
+ const FSlateLayoutTransform& InLayoutTransform = FSlateLayoutTransform(FVector2D(NoteOnX, NoteY));
+ // 根据NoteHeight绘制矩形
+ FSlateDrawElement::MakeBox(
+ OutDrawElements,
+ LayerId,
+ AllottedGeometry.ToPaintGeometry(FVector2D(NoteWidth, NoteHeight), InLayoutTransform),
+ NoteImage,
+ ESlateDrawEffect::None,
+ PianoRollEdit->IsNoteSelected(MidiMessage) ? NoteSelectedColor : NoteColor
+ );
+
+ const FString& NoteName = FMidiMessage::getMidiNoteName(NoteNumber, true, true);
+
+ // 绘制Note名称
+ FSlateDrawElement::MakeText(
+ OutDrawElements,
+ LayerId,
+ AllottedGeometry.ToPaintGeometry(FVector2D(NoteWidth, NoteHeight), InLayoutTransform),
+ NoteName,
+ FontInfo,
+ ESlateDrawEffect::None,
+ NoteTextColor
+ );
+ }
+ }
+
+ ++LayerId;
+ // 绘制当前MidiTick
+ {
+ const float CurrentMidiTickX = (CurrentMidiTick - RangeBegin) * FrameToPixel;
+ TArray Points;
+ Points.Add(FVector2f(CurrentMidiTickX, 0));
+ Points.Add(FVector2f(CurrentMidiTickX, Size.Y));
+ FSlateDrawElement::MakeLines(
+ OutDrawElements,
+ LayerId,
+ AllottedGeometry.ToPaintGeometry(),
+ Points,
+ ESlateDrawEffect::None,
+ FLinearColor::Red,
+ true,
+ 1
+ );
+ }
+
+ LayerId = PianoRollEdit->OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
+
+ return LayerId;
+}
+
+FReply SPianoRollPanel::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ return PianoRollEdit->OnMouseButtonDown(MyGeometry, MouseEvent);
+}
+
+FReply SPianoRollPanel::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ return PianoRollEdit->OnMouseButtonUp(MyGeometry, MouseEvent);
+}
+
+FReply SPianoRollPanel::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ return PianoRollEdit->OnMouseMove(MyGeometry, MouseEvent);
+}
+
+FReply SPianoRollPanel::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
+{
+ if (!InKeyEvent.IsRepeat() && InKeyEvent.GetKey() == EKeys::LeftShift)
+ OnRequestHScroll.ExecuteIfBound(true);
+ return PianoRollEdit->OnKeyDown(MyGeometry, InKeyEvent);
+}
+
+FReply SPianoRollPanel::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
+{
+ if (!InKeyEvent.IsRepeat() && InKeyEvent.GetKey() == EKeys::LeftShift)
+ OnRequestHScroll.ExecuteIfBound(false);
+
+ return PianoRollEdit->OnKeyUp(MyGeometry, InKeyEvent);
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.h b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.h
new file mode 100644
index 0000000..9348de5
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/PianoRollPanel/SPianoRollPanel.h
@@ -0,0 +1,90 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "PianoRollEdit.h"
+#include "SCompoundWidget.h"
+#include "SLeafWidget.h"
+#include "Midi/MidiMessageSequence.h"
+
+class FMidiMessage;
+class FMidiMessageSequence;
+
+DECLARE_DELEGATE_OneParam(FPianoRollPanelTargetRangeChanged, TRange)
+DECLARE_DELEGATE_OneParam(FPianoRollPanelYRequestUpdate, float /*Delta*/)
+DECLARE_DELEGATE_OneParam(FPianoRollPanelRequestHScroll, bool /*Delta*/)
+
+/**
+ *
+ */
+class ARONA_API SPianoRollPanel : public SLeafWidget
+{
+ friend class FPianoRollEdit;
+public:
+ SLATE_BEGIN_ARGS(SPianoRollPanel):
+ _SpacingLineColor(FLinearColor::Gray),
+ _NoteColor(FLinearColor::White),
+ _NoteSelectedColor(FLinearColor::Blue),
+ _NoteTextColor(FLinearColor::Black)
+ {
+ }
+
+ SLATE_EVENT(FPianoRollPanelTargetRangeChanged, OnTargetRangeChanged)
+ SLATE_EVENT(FPianoRollPanelYRequestUpdate, OnYRequestUpdate)
+ SLATE_EVENT(FPianoRollPanelRequestHScroll, OnRequestHScroll)
+
+ SLATE_ARGUMENT(const FSlateBrush*, NoteImage)
+
+ SLATE_ARGUMENT(FLinearColor, SpacingLineColor)
+ SLATE_ARGUMENT(FLinearColor, NoteColor)
+ SLATE_ARGUMENT(FLinearColor, NoteSelectedColor)
+ SLATE_ARGUMENT(FLinearColor, NoteTextColor)
+ SLATE_ARGUMENT(FSlateFontInfo, FontInfo)
+
+ SLATE_ARGUMENT(float, SpacingLineThickness)
+ SLATE_ARGUMENT(float, NoteHeight)
+
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FMidiMessageSequence* InMidiMessageSequence);
+
+ virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
+ virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override { return FVector2D(SequenceWidth, NoteHeight * 128); }
+
+ virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
+ virtual FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
+ virtual bool SupportsKeyboardFocus() const override { return true; }
+
+ int HeightToNoteNumber(float Height) const { return FMidiMessage::MaxNoteNumber - Height / NoteHeight + 1; }
+ // double PixelToMidiTick(float Pixel) const { return Pixel / FrameToPixel + TimeRange.GetLowerBoundValue(); }
+ AudioFrame PixelToFrame(float Pixel) const { return Pixel / FrameToPixel + TimeRange.GetLowerBoundValue(); }
+
+ FMidiMessageSequence* GetMidiMessageSequence() const { return MidiMessageSequence; }
+
+ TRange TimeRange;
+
+ FPianoRollPanelTargetRangeChanged OnTargetRangeChanged;
+ FPianoRollPanelYRequestUpdate OnYRequestUpdate;
+ FPianoRollPanelRequestHScroll OnRequestHScroll;
+
+ FLinearColor SpacingLineColor;
+ FLinearColor NoteColor;
+ FLinearColor NoteSelectedColor;
+ FLinearColor NoteTextColor;
+ FSlateFontInfo FontInfo;
+ TSharedPtr PianoRollEdit;
+ float SpacingLineThickness = 1.f;
+ float NoteHeight = 20.f;
+ float FrameToPixel = 0.2f;
+private:
+ float SequenceWidth = 100.f;
+ const FSlateBrush* BackgroundImage = nullptr;
+ const FSlateBrush* NoteImage = nullptr;
+ FMidiMessageSequence* MidiMessageSequence = nullptr;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/SPianoKey.cpp b/Source/Arona/UI/Widget/PianoRoll/SPianoKey.cpp
new file mode 100644
index 0000000..a1545cc
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/SPianoKey.cpp
@@ -0,0 +1,161 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SPianoKey.h"
+
+#include "FontMeasure.h"
+#include "SlateApplication.h"
+#include "SlateOptMacros.h"
+#include "Midi/MidiMessage.h"
+#include "PluginHost/PluginHost.h"
+#include "UI/Style/AronaStyle.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+bool IsBetweenBlackKey(int32 NoteNumber)
+{
+ return NoteNumber % 12 == 1 || NoteNumber % 12 == 3 || NoteNumber % 12 == 6 || NoteNumber % 12 == 8 || NoteNumber % 12 == 10;
+}
+
+void SPianoKey::Construct(const FArguments& InArgs, FPluginHost* InPluginHost)
+{
+ PluginHost = InPluginHost;
+ KeyHeight = InArgs._KeyHeight;
+ KeyWidth = InArgs._KeyWidth;
+}
+
+int32 SPianoKey::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
+{
+ const FVector2D Size = AllottedGeometry.GetLocalSize();
+ const float BlackKeyHeight = KeyHeight.Get(); // 黑键始终为KeyHeight
+ const float SemitoneHeight = BlackKeyHeight * 1.5f; // 半音高度
+ const float WholeToneHeight = SemitoneHeight * 2; // 全音高度
+ const TSharedRef FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService();
+
+ float CursorY = KeyHeight.Get() * FMidiMessage::MaxNoteNumber - (KeyHeight.Get() * 1.5);
+ FSlateFontInfo SlateFontInfo = FAronaStyle::GetFontInfo(DefaultFontName);
+ // 画白键
+ ++LayerId;
+ for (int32 i = 0; i < FMidiMessage::MaxNoteNumber + 1; ++i)
+ {
+ if (FMidiMessage::isMidiNoteBlack(i))
+ continue;
+ const bool IsBetweenBlack = IsBetweenBlackKey(i);
+ const float CurrentKeyHeight = IsBetweenBlack ? SemitoneHeight : WholeToneHeight;
+ const FSlateLayoutTransform& InLayoutTransform = FSlateLayoutTransform(FVector2D(0, CursorY));
+
+ // 画白键
+ FSlateDrawElement::MakeBox(
+ OutDrawElements,
+ LayerId,
+ AllottedGeometry.ToPaintGeometry(FVector2f(Size.X, CurrentKeyHeight), InLayoutTransform),
+ FAronaStyle::GetSlateBrush(WhiteKey)
+ );
+ CursorY -= CurrentKeyHeight;
+ }
+
+ // 画黑键
+ ++LayerId;
+ for (int32 i = 0; i < FMidiMessage::MaxNoteNumber + 1; ++i)
+ {
+ if (FMidiMessage::isMidiNoteWhite(i))
+ continue;
+ const FSlateLayoutTransform& InLayoutTransform = FSlateLayoutTransform(FVector2D(0, (FMidiMessage::MaxNoteNumber - i) * BlackKeyHeight));
+ // AllottedGeometry.ToPaintGeometry(FVector2f(0, (FMidiMessage::MaxNoteNumber - i) * BlackKeyHeight), FVector2f(Size.X * 0.7, BlackKeyHeight))
+ // 画黑键
+ FSlateDrawElement::MakeBox(
+ OutDrawElements,
+ LayerId,
+ AllottedGeometry.ToPaintGeometry(FVector2f(Size.X * 0.7, BlackKeyHeight), InLayoutTransform),
+ FAronaStyle::GetSlateBrush(BlackKey)
+ );
+ }
+
+ ++LayerId;
+ // 画字
+ for (int i = 0; i < FMidiMessage::MaxNoteNumber + 1; ++i)
+ {
+ FString MidiNoteName = FMidiMessage::getMidiNoteName(i, true, true);
+ // 计算字体大小
+ const float FontSize = FontMeasureService->Measure(MidiNoteName, SlateFontInfo).X;
+ const FSlateLayoutTransform& InLayoutTransform = FSlateLayoutTransform(FVector2D(Size.X - FontSize, (FMidiMessage::MaxNoteNumber - i) * BlackKeyHeight));
+
+ // 画字
+ FSlateDrawElement::MakeText(
+ OutDrawElements,
+ LayerId,
+ AllottedGeometry.ToPaintGeometry(FVector2f(Size.X, BlackKeyHeight), InLayoutTransform),
+ MidiNoteName,
+ SlateFontInfo,
+ ESlateDrawEffect::None,
+ FLinearColor::Black
+ );
+ }
+ return LayerId;
+}
+
+FVector2D SPianoKey::ComputeDesiredSize(float LayoutScaleMultiplier) const
+{
+ return FVector2D(KeyWidth.Get(), KeyHeight.Get() * FMidiMessage::MaxNoteNumber);
+}
+
+FReply SPianoKey::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
+ {
+ const FVector2D LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
+ const int32 NoteNumber = HeightToNoteNumber(LocalPos.Y);
+ if (NoteNumber >= 0 && NoteNumber <= FMidiMessage::MaxNoteNumber)
+ {
+ PluginHost->IncomingMidi.addEvent(FMidiMessage::noteOn(1, NoteNumber, WidthToVelocity(LocalPos.X)));
+ LastNoteNumber = NoteNumber;
+ }
+ return FReply::Handled().CaptureMouse(AsShared());
+ }
+ return FReply::Unhandled();
+}
+
+FReply SPianoKey::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
+ {
+ if (LastNoteNumber >= 0 && LastNoteNumber <= FMidiMessage::MaxNoteNumber)
+ {
+ PluginHost->IncomingMidi.addEvent(FMidiMessage::noteOff(1, LastNoteNumber, 0.f));
+ }
+ LastNoteNumber = -1;
+ return FReply::Handled().ReleaseMouseCapture();
+ }
+ return FReply::Unhandled();
+}
+
+FReply SPianoKey::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
+ {
+ const int32 CurrentNoteNumber = HeightToNoteNumber(MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()).Y);
+
+ if (LastNoteNumber != CurrentNoteNumber)
+ {
+ if (LastNoteNumber != -1)
+ PluginHost->IncomingMidi.addEvent(FMidiMessage::noteOff(1, LastNoteNumber, 0.f));
+ LastNoteNumber = CurrentNoteNumber;
+
+ const float Velocity = WidthToVelocity(MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()).X);
+ PluginHost->IncomingMidi.addEvent(FMidiMessage::noteOn(1, CurrentNoteNumber, Velocity));
+ }
+ return FReply::Handled();
+ }
+ return FReply::Unhandled();
+}
+
+int32 SPianoKey::HeightToNoteNumber(float Height) const
+{
+ return FMidiMessage::MaxNoteNumber - Height / KeyHeight.Get();
+}
+
+float SPianoKey::WidthToVelocity(float Width) const
+{
+ return FMath::Min(Width / KeyWidth.Get(), 1.f);
+}
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/PianoRoll/SPianoKey.h b/Source/Arona/UI/Widget/PianoRoll/SPianoKey.h
new file mode 100644
index 0000000..67a72d3
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/SPianoKey.h
@@ -0,0 +1,41 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SLeafWidget.h"
+
+class FPluginHost;
+/**
+ *
+ */
+class ARONA_API SPianoKey : public SLeafWidget
+{
+public:
+ SLATE_BEGIN_ARGS(SPianoKey)
+ {
+ }
+ SLATE_ATTRIBUTE(float, KeyHeight)
+ SLATE_ATTRIBUTE(float, KeyWidth)
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FPluginHost* InPluginHost);
+
+
+ virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
+ virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override;
+
+ virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+ virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+private:
+ int32 HeightToNoteNumber(float Height) const;
+ float WidthToVelocity(float Width) const;
+
+ int32 LastNoteNumber = -1;
+ FPluginHost* PluginHost = nullptr;
+ TAttribute KeyHeight; // 白键高度
+ TAttribute KeyWidth;
+};
diff --git a/Source/Arona/UI/Widget/PianoRoll/SPianoRoll.cpp b/Source/Arona/UI/Widget/PianoRoll/SPianoRoll.cpp
new file mode 100644
index 0000000..298478b
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/SPianoRoll.cpp
@@ -0,0 +1,191 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "SPianoRoll.h"
+
+#include "SBackgroundBlur.h"
+#include "SGridPanel.h"
+#include "SImage.h"
+#include "SlateOptMacros.h"
+#include "SOverlay.h"
+#include "SPianoKey.h"
+#include "SScaleBox.h"
+#include "SScrollBar.h"
+#include "SScrollBox.h"
+#include "Midi/MidiMessageSequence.h"
+#include "Singleton/MidiSequencer.h"
+#include "PianoRollPanel/SPianoRollPanel.h"
+#include "UI/Style/AronaStyle.h"
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SPianoRoll::Construct(const FArguments& InArgs, FMidiMessageSequence* InMidiMessageSequence, FPluginHost* InPluginHost)
+{
+ MidiMessageSequence = InMidiMessageSequence;
+ VerticalScrollBar = SNew(SScrollBar)
+ .Orientation(Orient_Vertical)
+ .AlwaysShowScrollbar(true)
+ .AlwaysShowScrollbarTrack(true);
+
+ ChildSlot
+ [
+ SNew(SGridPanel)
+ .FillColumn(0, 1)
+ .FillRow(0, 1)
+
+ +SGridPanel::Slot(0, 0)
+ [
+ SNew(SOverlay)
+ +SOverlay::Slot()
+ [
+ SNew(SScaleBox)
+ .Stretch(EStretch::ScaleToFill)
+ .HAlign(HAlign_Center)
+ .VAlign(VAlign_Center)
+ [
+ SNew(SImage)
+ .Image(FAronaStyle::GetSlateBrush(PianoRollBackground))
+ ]
+ ]
+ +SOverlay::Slot()
+ [
+ SAssignNew(ScrollBox, SScrollBox)
+ .ConsumeMouseWheel(EConsumeMouseWheel::Always)
+ .ExternalScrollbar(VerticalScrollBar)
+ .AnimateWheelScrolling(false)
+ .Visibility(EVisibility::SelfHitTestInvisible)
+ +SScrollBox::Slot()
+ [
+ SNew(SHorizontalBox)
+ +SHorizontalBox::Slot()
+ .AutoWidth()
+ [
+ SNew(SPianoKey, InPluginHost)
+ .KeyHeight(KeyHeight)
+ .KeyWidth(100)
+ ]
+ +SHorizontalBox::Slot()
+ .FillWidth(1.f)
+ [
+ SAssignNew(PianoRollPanel, SPianoRollPanel, MidiMessageSequence)
+ .FontInfo(FAronaStyle::GetFontInfo(DefaultFontName))
+ .NoteImage(FAronaStyle::GetSlateBrush(VolumeMeterBar))
+ .SpacingLineColor(FLinearColor::Green)
+ .NoteHeight(KeyHeight)
+ .OnTargetRangeChanged(this, &SPianoRoll::SetFrameRange)
+ .OnYRequestUpdate(this, &SPianoRoll::AddYDelta)
+ .OnRequestHScroll(this, &SPianoRoll::OnPanelRequestHScroll)
+ ]
+ ]
+ ]
+ ]
+ +SGridPanel::Slot(1, 0)
+ [
+ VerticalScrollBar.ToSharedRef()
+ ]
+ +SGridPanel::Slot(0, 1)
+ [
+ SAssignNew(HorizontalScrollBar, SScrollBar)
+ .Orientation(Orient_Horizontal)
+ .AlwaysShowScrollbar(true)
+ .AlwaysShowScrollbarTrack(true)
+ .OnUserScrolled(this, &SPianoRoll::OnHorizontalScrollBarChanged)
+ ]
+ ];
+
+ TargetMidiTickRange = PianoRollPanel->TimeRange;
+ const double EndTime = MidiMessageSequence->getEndTime();
+ HorizontalScrollBar->SetState(0, TargetMidiTickRange.Size() / EndTime, false);
+}
+
+void SPianoRoll::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
+{
+ SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
+ if (AllottedGeometry.Size.X == 0)
+ return;
+
+ // const double Lower = FMath::FInterpTo(PianoRollPanel->TimeRange.GetLowerBoundValue(), TargetMidiTickRange.GetLowerBoundValue(), InDeltaTime, 15.f);
+ // const double Upper = FMath::FInterpTo(PianoRollPanel->TimeRange.GetUpperBoundValue(), TargetMidiTickRange.GetUpperBoundValue(), InDeltaTime, 15.f);
+ const double Lower = TargetMidiTickRange.GetLowerBoundValue();
+ const double Upper = TargetMidiTickRange.GetUpperBoundValue();
+ PianoRollPanel->TimeRange.SetLowerBoundValue(Lower);
+ PianoRollPanel->TimeRange.SetUpperBoundValue(Upper);
+
+ const float MidiTickDuration = PianoRollPanel->TimeRange.Size();
+ const double EndTime = MidiMessageSequence->getEndTime();
+ HorizontalScrollBar->SetState(Lower / EndTime, MidiTickDuration / EndTime, false);
+}
+
+FReply SPianoRoll::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
+{
+ if (EnableHorizontalScroll)
+ {
+ AddFrameRangeDelta(MouseEvent.GetWheelDelta() * -FMidiSequencer::Get().GetTicksPerQuarter());
+ return FReply::Unhandled();
+ }
+ return FReply::Unhandled();
+}
+
+void SPianoRoll::AddFrameRangeDelta(AudioFrame InDelta)
+{
+ double Lower = TargetMidiTickRange.GetLowerBoundValue() + InDelta;
+ double Upper = TargetMidiTickRange.GetUpperBoundValue() + InDelta;
+ if (Lower < 0)
+ {
+ Upper -= Lower;
+ Lower = 0;
+ }
+
+ TargetMidiTickRange = TRange(Lower, Upper);
+}
+
+void SPianoRoll::SetFrameRange(TRange InMidiRange)
+{
+ TargetMidiTickRange = InMidiRange;
+}
+
+void SPianoRoll::AddYDelta(float InDelta)
+{
+ ScrollBox->SetScrollOffset(ScrollBox->GetScrollOffset() + InDelta);
+}
+
+void SPianoRoll::InitScrollBar()
+{
+ OnHorizontalScrollBarChanged(0);
+}
+
+TSharedPtr SPianoRoll::GetFocusWidget()
+{
+ return PianoRollPanel;
+}
+
+void SPianoRoll::OnHorizontalScrollBarChanged(float InScrollOffsetFraction)
+{
+ const auto& PanelSize = PianoRollPanel->GetTickSpaceGeometry().Size;
+ if (PanelSize.X == 0)
+ return;
+
+ const MidiTick EndTime = MidiMessageSequence->getEndTime();
+ const MidiTick MidiTickDuration = PianoRollPanel->TimeRange.Size();
+ const MidiTick StartTick = EndTime * InScrollOffsetFraction;
+
+ TargetMidiTickRange = TRange(StartTick.Frames(), StartTick.Frames() + MidiTickDuration.Frames());
+
+ // HorizontalScrollBar->SetState(InScrollOffsetFraction, MidiTickDuration / EndTime, false);
+}
+
+void SPianoRoll::OnPanelRequestHScroll(bool InStatus)
+{
+ if (InStatus)
+ {
+ EnableHorizontalScroll = true;
+ ScrollBox->SetConsumeMouseWheel(EConsumeMouseWheel::Never);
+ }
+ else
+ {
+ EnableHorizontalScroll = false;
+ ScrollBox->SetConsumeMouseWheel(EConsumeMouseWheel::Always);
+ }
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
diff --git a/Source/Arona/UI/Widget/PianoRoll/SPianoRoll.h b/Source/Arona/UI/Widget/PianoRoll/SPianoRoll.h
new file mode 100644
index 0000000..b29963e
--- /dev/null
+++ b/Source/Arona/UI/Widget/PianoRoll/SPianoRoll.h
@@ -0,0 +1,56 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SCompoundWidget.h"
+#include "Midi/Time/TimePos.h"
+#include "UI/Widget/IChildWindow.h"
+
+class FPluginHost;
+class SScrollBox;
+class FMidiMessageSequence;
+class SScrollBar;
+class SPianoRollPanel;
+/**
+ *
+ */
+class ARONA_API SPianoRoll : public SCompoundWidget, public IChildWindow
+{
+public:
+ SLATE_BEGIN_ARGS(SPianoRoll)
+ {
+ }
+
+ SLATE_END_ARGS()
+
+ /** Constructs this widget with InArgs */
+ void Construct(const FArguments& InArgs, FMidiMessageSequence* InMidiMessageSequence, FPluginHost* InPluginHost);
+
+ virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
+
+ virtual FReply OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
+
+ void AddFrameRangeDelta(AudioFrame InDelta);
+ void SetFrameRange(TRange InMidiRange);
+
+ void AddYDelta(float InDelta);
+
+ void InitScrollBar();
+
+ virtual TSharedRef GetWidget() override { return AsShared(); }
+ virtual TSharedPtr GetFocusWidget() override;
+
+private:
+ void OnHorizontalScrollBarChanged(float InScrollOffsetFraction);
+ void OnPanelRequestHScroll(bool InStatus);
+
+ float KeyHeight = 20.f;
+ TSharedPtr PianoRollPanel;
+ TSharedPtr ScrollBox;
+ TSharedPtr VerticalScrollBar;
+ TSharedPtr HorizontalScrollBar;
+ TRange TargetMidiTickRange;
+ FMidiMessageSequence* MidiMessageSequence = nullptr;
+ bool EnableHorizontalScroll = false;
+};
diff --git a/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditAction.cpp b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditAction.cpp
new file mode 100644
index 0000000..8aa4054
--- /dev/null
+++ b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditAction.cpp
@@ -0,0 +1,8 @@
+#include "PlayListEditAction.h"
+
+void FPlayListEditAction::OnActive(FPlayListEdit& Edit)
+{
+ FPlayListEditTool::OnActive(Edit);
+ Execute(Edit);
+ Edit.ClearTempTool();
+}
diff --git a/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditAction.h b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditAction.h
new file mode 100644
index 0000000..946444b
--- /dev/null
+++ b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditAction.h
@@ -0,0 +1,13 @@
+#pragma once
+#include "PlayListEditTool.h"
+
+class FPlayListEditAction : public FPlayListEditTool
+{
+public:
+ FPlayListEditAction(EPlayListToolType InToolType) : FPlayListEditTool(InToolType)
+ {
+ }
+ virtual void OnActive(FPlayListEdit& Edit) override;
+protected:
+ virtual void Execute(FPlayListEdit& Edit) = 0;
+};
diff --git a/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool.cpp b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool.cpp
new file mode 100644
index 0000000..2f677ed
--- /dev/null
+++ b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool.cpp
@@ -0,0 +1,9 @@
+#include "PlayListEditTool.h"
+
+void FPlayListEditTool::OnActive(FPlayListEdit& Edit)
+{
+}
+
+void FPlayListEditTool::Clear(FPlayListEdit& Edit)
+{
+}
diff --git a/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool.h b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool.h
new file mode 100644
index 0000000..facf5e1
--- /dev/null
+++ b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "PaintArgs.h"
+#include "Reply.h"
+#include "WidgetStyle.h"
+#include "UI/Widget/PlayList/PlayListPanel/PlayListEdit.h"
+
+class FPlayListEditTool
+{
+public:
+ FPlayListEditTool(EPlayListToolType InToolType) : ToolType(InToolType)
+ {
+ }
+
+ virtual ~FPlayListEditTool() = default;
+
+ virtual void OnActive(FPlayListEdit& Edit);
+ virtual void Clear(FPlayListEdit& Edit);
+
+ virtual void OnMouseButtonDown(FPlayListEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { }
+ virtual void OnMouseButtonUp(FPlayListEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { }
+ virtual void OnMouseMove(FPlayListEdit& Edit, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { }
+
+ virtual void OnBeginDrag(FPlayListEdit& Edit, FVector2f InMouseStartPos) { }
+ virtual void OnEndDrag(FPlayListEdit& Edit, FVector2f InMouseEndPos) { }
+
+ virtual int32 OnPaint(const FPlayListEdit& Edit, const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { return LayerId; }
+
+ EPlayListToolType GetToolType() const { return ToolType; }
+private:
+ EPlayListToolType ToolType;
+};
diff --git a/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_DragView.cpp b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_DragView.cpp
new file mode 100644
index 0000000..1c98b9e
--- /dev/null
+++ b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_DragView.cpp
@@ -0,0 +1 @@
+#include "PlayListEditTool_DragView.h"
diff --git a/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_DragView.h b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_DragView.h
new file mode 100644
index 0000000..af201e4
--- /dev/null
+++ b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_DragView.h
@@ -0,0 +1,11 @@
+#pragma once
+#include "PlayListEditTool.h"
+
+class FPlayListEditTool_DragView : public FPlayListEditTool
+{
+public:
+ FPlayListEditTool_DragView() : FPlayListEditTool(EPlayListToolType::DragView) {}
+
+
+private:
+};
diff --git a/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_Select.cpp b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_Select.cpp
new file mode 100644
index 0000000..8148ec7
--- /dev/null
+++ b/Source/Arona/UI/Widget/PlayList/PlayListPanel/EditTool/PlayListEditTool_Select.cpp
@@ -0,0 +1,80 @@
+#include "PlayListEditTool_Select.h"
+
+#include "UI/Widget/PlayList/PlayListPanel/SPlayListPanel.h"
+
+void FPlayListEditTool_Select::Clear(FPlayListEdit& Edit)
+{
+ FPlayListEditTool::Clear(Edit);
+ RectSelecting = false;
+}
+
+void FPlayListEditTool_Select::OnMouseMove(FPlayListEdit& Edit, const FGeometry& MyGeometry,
+ const FPointerEvent& MouseEvent)
+{
+ MouseCurrentPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
+}
+
+void FPlayListEditTool_Select::OnBeginDrag(FPlayListEdit& Edit, FVector2f InMouseStartPos)
+{
+ RectSelecting = true;
+}
+
+void FPlayListEditTool_Select::OnEndDrag(FPlayListEdit& Edit, FVector2f InMouseEndPos)
+{
+ RectSelecting = false;
+
+ const FVector2f& MouseDownPos = Edit.GetMouseDownPos();
+ const TSharedPtr