diff --git a/Builder.sln b/Builder.sln index 55988f54..e47765b0 100755 --- a/Builder.sln +++ b/Builder.sln @@ -35,226 +35,312 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutomapMode", "Source\Plugi EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vpo_dll", "Source\Plugins\vpo_dll\vpo_dll.vcxproj", "{29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreeDFloorMode", "Source\Plugins\3DFloorMode\ThreeDFloorMode.csproj", "{88CFD996-027B-4CBE-9828-26B2728B6127}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug + Profiler|Any CPU = Debug + Profiler|Any CPU Debug + Profiler|x64 = Debug + Profiler|x64 Debug + Profiler|x86 = Debug + Profiler|x86 + Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Release + Profiler|Any CPU = Release + Profiler|Any CPU Release + Profiler|x64 = Release + Profiler|x64 Release + Profiler|x86 = Release + Profiler|x86 + Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug|Any CPU.ActiveCfg = Debug|x86 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug|x64.ActiveCfg = Debug|x64 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug|x64.Build.0 = Debug|x64 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug|x86.ActiveCfg = Debug|x86 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Debug|x86.Build.0 = Debug|x86 + {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|Any CPU.ActiveCfg = Release|x86 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x64.ActiveCfg = Release|x64 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x64.Build.0 = Release|x64 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x86.ActiveCfg = Release|x86 {818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x86.Build.0 = Release|x86 + {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug|Any CPU.ActiveCfg = Debug|x86 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug|x64.ActiveCfg = Debug|x64 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug|x64.Build.0 = Debug|x64 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug|x86.ActiveCfg = Debug|x86 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Debug|x86.Build.0 = Debug|x86 + {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release|Any CPU.ActiveCfg = Release|x86 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release|x64.ActiveCfg = Release|x64 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release|x64.Build.0 = Release|x64 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release|x86.ActiveCfg = Release|x86 {B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release|x86.Build.0 = Release|x86 + {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug|Any CPU.ActiveCfg = Debug|x86 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug|x64.ActiveCfg = Debug|x64 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug|x64.Build.0 = Debug|x64 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug|x86.ActiveCfg = Debug|x86 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Debug|x86.Build.0 = Debug|x86 + {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release|Any CPU.ActiveCfg = Release|x86 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release|x64.ActiveCfg = Release|x64 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release|x64.Build.0 = Release|x64 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release|x86.ActiveCfg = Release|x86 {B859BE0F-A992-476D-A642-FA8EFE94AAA5}.Release|x86.Build.0 = Release|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Any CPU.ActiveCfg = Debug|x86 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|x64.ActiveCfg = Debug|x64 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|x64.Build.0 = Debug|x64 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|x86.ActiveCfg = Debug|x86 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|x86.Build.0 = Debug|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|Any CPU.ActiveCfg = Release|x86 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|x64.ActiveCfg = Release|x64 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|x64.Build.0 = Release|x64 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|x86.ActiveCfg = Release|x86 {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|x86.Build.0 = Release|x86 + {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug|Any CPU.ActiveCfg = Debug|x86 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug|x64.ActiveCfg = Debug|x64 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug|x64.Build.0 = Debug|x64 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug|x86.ActiveCfg = Debug|x86 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Debug|x86.Build.0 = Debug|x86 + {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release|Any CPU.ActiveCfg = Release|x86 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release|x64.ActiveCfg = Release|x64 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release|x64.Build.0 = Release|x64 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release|x86.ActiveCfg = Release|x86 {BE7917F3-E6FE-4D5B-8FA9-B8E7668AC731}.Release|x86.Build.0 = Release|x86 + {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug|Any CPU.ActiveCfg = Debug|x86 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug|x64.ActiveCfg = Debug|x64 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug|x64.Build.0 = Debug|x64 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug|x86.ActiveCfg = Debug|x86 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Debug|x86.Build.0 = Debug|x86 + {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release|Any CPU.ActiveCfg = Release|x86 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release|x64.ActiveCfg = Release|x64 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release|x64.Build.0 = Release|x64 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release|x86.ActiveCfg = Release|x86 {58BD8A5B-1B48-435D-8473-A92F27D06C49}.Release|x86.Build.0 = Release|x86 + {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug|Any CPU.ActiveCfg = Debug|x86 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug|x64.ActiveCfg = Debug|x64 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug|x64.Build.0 = Debug|x64 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug|x86.ActiveCfg = Debug|x86 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Debug|x86.Build.0 = Debug|x86 + {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release|Any CPU.ActiveCfg = Release|x86 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release|x64.ActiveCfg = Release|x64 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release|x64.Build.0 = Release|x64 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release|x86.ActiveCfg = Release|x86 {9F244231-6A0C-42A6-87C5-ED9620DEE096}.Release|x86.Build.0 = Release|x86 + {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug|Any CPU.ActiveCfg = Debug|x86 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug|x64.ActiveCfg = Debug|x64 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug|x64.Build.0 = Debug|x64 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug|x86.ActiveCfg = Debug|x86 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Debug|x86.Build.0 = Debug|x86 + {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release|Any CPU.ActiveCfg = Release|x86 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release|x64.ActiveCfg = Release|x64 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release|x64.Build.0 = Release|x64 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release|x86.ActiveCfg = Release|x86 {F49EFF6D-51CB-4E49-8223-AAE653C5B62F}.Release|x86.Build.0 = Release|x86 + {CF670175-7099-4090-A330-EE25C7230139}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {CF670175-7099-4090-A330-EE25C7230139}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {CF670175-7099-4090-A330-EE25C7230139}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {CF670175-7099-4090-A330-EE25C7230139}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {CF670175-7099-4090-A330-EE25C7230139}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {CF670175-7099-4090-A330-EE25C7230139}.Debug|Any CPU.ActiveCfg = Debug|x86 {CF670175-7099-4090-A330-EE25C7230139}.Debug|x64.ActiveCfg = Debug|x64 {CF670175-7099-4090-A330-EE25C7230139}.Debug|x64.Build.0 = Debug|x64 {CF670175-7099-4090-A330-EE25C7230139}.Debug|x86.ActiveCfg = Debug|x86 {CF670175-7099-4090-A330-EE25C7230139}.Debug|x86.Build.0 = Debug|x86 + {CF670175-7099-4090-A330-EE25C7230139}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {CF670175-7099-4090-A330-EE25C7230139}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {CF670175-7099-4090-A330-EE25C7230139}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {CF670175-7099-4090-A330-EE25C7230139}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {CF670175-7099-4090-A330-EE25C7230139}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {CF670175-7099-4090-A330-EE25C7230139}.Release|Any CPU.ActiveCfg = Release|x86 {CF670175-7099-4090-A330-EE25C7230139}.Release|x64.ActiveCfg = Release|x64 {CF670175-7099-4090-A330-EE25C7230139}.Release|x64.Build.0 = Release|x64 {CF670175-7099-4090-A330-EE25C7230139}.Release|x86.ActiveCfg = Release|x86 {CF670175-7099-4090-A330-EE25C7230139}.Release|x86.Build.0 = Release|x86 + {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug|Any CPU.ActiveCfg = Debug|x86 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug|x64.ActiveCfg = Debug|x64 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug|x64.Build.0 = Debug|x64 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug|x86.ActiveCfg = Debug|x86 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Debug|x86.Build.0 = Debug|x86 + {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release|Any CPU.ActiveCfg = Release|x86 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release|x64.ActiveCfg = Release|x64 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release|x64.Build.0 = Release|x64 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release|x86.ActiveCfg = Release|x86 {F59B344C-DD50-4DB7-ADDD-56AAD66450AF}.Release|x86.Build.0 = Release|x86 + {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug + Profiler|Any CPU.ActiveCfg = Debug + Profiler|x86 {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug + Profiler|x64.ActiveCfg = Debug + Profiler|x64 {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug + Profiler|x64.Build.0 = Debug + Profiler|x64 {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug + Profiler|x86.ActiveCfg = Debug + Profiler|x86 {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug + Profiler|x86.Build.0 = Debug + Profiler|x86 + {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug|Any CPU.ActiveCfg = Debug|x86 {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug|x64.ActiveCfg = Debug|x64 {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug|x64.Build.0 = Debug|x64 {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug|x86.ActiveCfg = Debug|x86 {3F365121-906B-409D-BB1E-37E0A78056C2}.Debug|x86.Build.0 = Debug|x86 + {3F365121-906B-409D-BB1E-37E0A78056C2}.Release + Profiler|Any CPU.ActiveCfg = Release + Profiler|x86 {3F365121-906B-409D-BB1E-37E0A78056C2}.Release + Profiler|x64.ActiveCfg = Release + Profiler|x64 {3F365121-906B-409D-BB1E-37E0A78056C2}.Release + Profiler|x64.Build.0 = Release + Profiler|x64 {3F365121-906B-409D-BB1E-37E0A78056C2}.Release + Profiler|x86.ActiveCfg = Release + Profiler|x86 {3F365121-906B-409D-BB1E-37E0A78056C2}.Release + Profiler|x86.Build.0 = Release + Profiler|x86 + {3F365121-906B-409D-BB1E-37E0A78056C2}.Release|Any CPU.ActiveCfg = Release|x86 {3F365121-906B-409D-BB1E-37E0A78056C2}.Release|x64.ActiveCfg = Release|x64 {3F365121-906B-409D-BB1E-37E0A78056C2}.Release|x64.Build.0 = Release|x64 {3F365121-906B-409D-BB1E-37E0A78056C2}.Release|x86.ActiveCfg = Release|x86 {3F365121-906B-409D-BB1E-37E0A78056C2}.Release|x86.Build.0 = Release|x86 + {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug + Profiler|Any CPU.ActiveCfg = Release|x86 + {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug + Profiler|Any CPU.Build.0 = Release|x86 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug + Profiler|x64.ActiveCfg = Debug|x64 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug + Profiler|x64.Build.0 = Debug|x64 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug + Profiler|x86.ActiveCfg = Debug|x86 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug + Profiler|x86.Build.0 = Debug|x86 + {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug|Any CPU.ActiveCfg = Debug|x86 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug|x64.ActiveCfg = Debug|x64 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug|x64.Build.0 = Debug|x64 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug|x86.ActiveCfg = Debug|x86 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Debug|x86.Build.0 = Debug|x86 + {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release + Profiler|Any CPU.ActiveCfg = Release|x86 + {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release + Profiler|Any CPU.Build.0 = Release|x86 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release + Profiler|x64.ActiveCfg = Release|x64 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release + Profiler|x64.Build.0 = Release|x64 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release + Profiler|x86.ActiveCfg = Release|x86 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release + Profiler|x86.Build.0 = Release|x86 + {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release|Any CPU.ActiveCfg = Release|x86 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release|x64.ActiveCfg = Release|x64 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release|x64.Build.0 = Release|x64 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release|x86.ActiveCfg = Release|x86 {B33F68D5-1335-400C-A1D7-7F5602A030EF}.Release|x86.Build.0 = Release|x86 + {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug + Profiler|Any CPU.ActiveCfg = Release|x64 + {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug + Profiler|Any CPU.Build.0 = Release|x64 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug + Profiler|x64.ActiveCfg = Debug|x64 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug + Profiler|x64.Build.0 = Debug|x64 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug + Profiler|x86.ActiveCfg = Debug|Win32 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug + Profiler|x86.Build.0 = Debug|Win32 + {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug|Any CPU.ActiveCfg = Debug|Win32 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug|x64.ActiveCfg = Debug|x64 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug|x64.Build.0 = Debug|x64 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug|x86.ActiveCfg = Debug|Win32 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Debug|x86.Build.0 = Debug|Win32 + {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release + Profiler|Any CPU.ActiveCfg = Release|x64 + {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release + Profiler|Any CPU.Build.0 = Release|x64 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release + Profiler|x64.ActiveCfg = Release|Win32 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release + Profiler|x64.Build.0 = Release|Win32 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release + Profiler|x86.ActiveCfg = Release|Win32 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release + Profiler|x86.Build.0 = Release|Win32 + {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release|Any CPU.ActiveCfg = Release|Win32 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release|x64.ActiveCfg = Release|x64 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release|x64.Build.0 = Release|x64 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release|x86.ActiveCfg = Release|Win32 {29C8D76F-DE3D-482D-AD7D-B86BBD0824DE}.Release|x86.Build.0 = Release|Win32 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug + Profiler|Any CPU.ActiveCfg = Debug|Any CPU + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug + Profiler|Any CPU.Build.0 = Debug|Any CPU + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug + Profiler|x64.ActiveCfg = Debug|x64 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug + Profiler|x64.Build.0 = Debug|x64 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug + Profiler|x86.ActiveCfg = Debug|x86 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug + Profiler|x86.Build.0 = Debug|x86 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug|x64.ActiveCfg = Debug|x64 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug|x64.Build.0 = Debug|x64 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug|x86.ActiveCfg = Debug|x86 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Debug|x86.Build.0 = Debug|x86 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release + Profiler|Any CPU.ActiveCfg = Release|Any CPU + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release + Profiler|Any CPU.Build.0 = Release|Any CPU + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release + Profiler|x64.ActiveCfg = Release|x64 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release + Profiler|x64.Build.0 = Release|x64 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release + Profiler|x86.ActiveCfg = Release|x86 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release + Profiler|x86.Build.0 = Release|x86 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release|Any CPU.Build.0 = Release|Any CPU + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release|x64.ActiveCfg = Release|x64 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release|x64.Build.0 = Release|x64 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release|x86.ActiveCfg = Release|x86 + {88CFD996-027B-4CBE-9828-26B2728B6127}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Plugins/3DFloorMode/BuilderPlug.cs b/Source/Plugins/3DFloorMode/BuilderPlug.cs new file mode 100644 index 00000000..d9d0dbaa --- /dev/null +++ b/Source/Plugins/3DFloorMode/BuilderPlug.cs @@ -0,0 +1,1069 @@ + +#region ================== Copyright (c) 2014 Boris Iwanski + +/* + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Linq; +using System.Diagnostics; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using System.Drawing; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.BuilderModes; +// using CodeImp.DoomBuilder.GZBuilder.Geometry; +using CodeImp.DoomBuilder.VisualModes; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + // + // MANDATORY: The plug! + // This is an important class to the Doom Builder core. Every plugin must + // have exactly 1 class that inherits from Plug. When the plugin is loaded, + // this class is instantiated and used to receive events from the core. + // Make sure the class is public, because only public classes can be seen + // by the core. + // + [Flags] + public enum PlaneType + { + Floor = 1, + Ceiling = 2, + Bottom = 4, // Floor of 3D floor control sector + Top = 8 // Ceiling of 3D floor control sector + } + + public enum LabelDisplayOption + { + Always, + Never, + WhenHighlighted, + } + + public class BuilderPlug : Plug + { + #region ================== Variables + + private bool additiveselect; + private bool autoclearselection; + private MenusForm menusform; + private bool usehighlight; + private ControlSectorArea controlsectorarea; + private float highlightsloperange; + private List slopevertexgroups; + private float stitchrange; + private Sector slopedatasector; + private bool updateafteraction; + private string updateafteractionname; + private LabelDisplayOption sectorlabeldisplayoption; + private LabelDisplayOption slopevertexlabeldisplayoption; + private PreferencesForm preferencesform; + + // TMP + public List drawlines; + public List drawpoints; + + #endregion + + #region ================== Properties + + public bool AdditiveSelect { get { return additiveselect; } } + public bool AutoClearSelection { get { return autoclearselection; } } + public MenusForm MenusForm { get { return menusform; } } + public bool UseHighlight + { + get + { + return usehighlight; + } + set + { + usehighlight = value; + General.Map.Renderer3D.ShowSelection = usehighlight; + General.Map.Renderer3D.ShowHighlight = usehighlight; + } + } + public ControlSectorArea ControlSectorArea { get { return controlsectorarea; } } + public float HighlightSlopeRange { get { return highlightsloperange; } } + public List SlopeVertexGroups { get { return slopevertexgroups; } set { slopevertexgroups = value; } } + public float StitchRange { get { return stitchrange; } } + + public Sector SlopeDataSector { get { return slopedatasector; } set { slopedatasector = value; } } + + public LabelDisplayOption SectorLabelDisplayOption { get { return sectorlabeldisplayoption; } set { sectorlabeldisplayoption = value; } } + public LabelDisplayOption SlopeVertexLabelDisplayOption { get { return slopevertexlabeldisplayoption; } set { slopevertexlabeldisplayoption = value; } } + + #endregion + + // Static instance. We can't use a real static class, because BuilderPlug must + // be instantiated by the core, so we keep a static reference. (this technique + // should be familiar to object-oriented programmers) + private static BuilderPlug me; + + // Lines tagged to the selected sectors + private static ThreeDFloorEditorWindow tdfew = new ThreeDFloorEditorWindow(); + + public static ThreeDFloorEditorWindow TDFEW { get { return tdfew; } } + + // Static property to access the BuilderPlug + public static BuilderPlug Me { get { return me; } } + + // This plugin relies on some functionality that wasn't there in older versions + public override int MinimumRevision { get { return 1310; } } + + // This event is called when the plugin is initialized + public override void OnInitialize() + { + base.OnInitialize(); + + usehighlight = true; + + LoadSettings(); + + slopevertexgroups = new List(); + + //controlsectorarea = new ControlSectorArea(-512, 0, 512, 0, -128, -64, 128, 64, 64, 56); + + // This binds the methods in this class that have the BeginAction + // and EndAction attributes with their actions. Without this, the + // attributes are useless. Note that in classes derived from EditMode + // this is not needed, because they are bound automatically when the + // editing mode is engaged. + General.Actions.BindMethods(this); + + menusform = new MenusForm(); + + // TODO: Add DB2 version check so that old DB2 versions won't crash + // General.ErrorLogger.Add(ErrorType.Error, "zomg!"); + + // Keep a static reference + me = this; + + // TMP + drawlines = new List(); + drawpoints = new List(); + } + + // This is called when the plugin is terminated + public override void Dispose() + { + base.Dispose(); + + // This must be called to remove bound methods for actions. + General.Actions.UnbindMethods(this); + } + + public override void OnMapNewEnd() + { + base.OnMapNewEnd(); + + controlsectorarea = new ControlSectorArea(-512, 0, 512, 0, 64, 56); + BuilderPlug.Me.ControlSectorArea.LoadConfig(); + + slopevertexgroups.Clear(); + + slopedatasector = null; + } + + public override void OnMapOpenEnd() + { + base.OnMapOpenEnd(); + + controlsectorarea = new ControlSectorArea(-512, 0, 512, 0, 64, 56); + BuilderPlug.Me.ControlSectorArea.LoadConfig(); + + // Try to find the slope data sector and store slope information in it + slopedatasector = GetSlopeDataSector(); + + if (slopedatasector != null) + LoadSlopeVertexGroupsFromSector(); + } + + public override void OnUndoEnd() + { + base.OnUndoEnd(); + + // Load slope vertex data from the dummy sector + LoadSlopeVertexGroupsFromSector(); + } + + public override void OnRedoEnd() + { + base.OnRedoEnd(); + + // Load slope vertex data from the dummy sector + LoadSlopeVertexGroupsFromSector(); + } + + public override void OnActionBegin(CodeImp.DoomBuilder.Actions.Action action) + { + base.OnActionBegin(action); + + string[] monitoractions = { + "buildermodes_raisesector8", "buildermodes_lowersector8", "buildermodes_raisesector1", + "buildermodes_lowersector1", "builder_visualedit", "builder_classicedit" + }; + + if (General.Editing.Mode is SlopeMode) + return; + + if (monitoractions.Contains(action.Name)) + { + updateafteraction = true; + updateafteractionname = action.Name; + } + //else + // updateafteraction = false; + } + + public override void OnActionEnd(CodeImp.DoomBuilder.Actions.Action action) + { + base.OnActionEnd(action); + + Debug.WriteLine("SLOPE: OnActionEnd (" + action.Name + ")"); + + if (!updateafteraction && action.Name != updateafteractionname) + return; + + updateafteraction = false; + + Debug.WriteLine("SLOPE: Acting for OnActionEnd (" + action.Name + ")"); + + Dictionary updatesvgs = new Dictionary(); + + // Find SVGs that needs to be updated, and change the SV z positions + foreach (SlopeVertexGroup svg in slopevertexgroups) + { + bool update = false; + Dictionary> newheights = new Dictionary>(); + + foreach (Sector s in svg.Sectors) + { + if (s.Fields == null) + continue; + + if ((svg.SectorPlanes[s] & PlaneType.Floor) == PlaneType.Floor) + { + if (s.Fields.ContainsKey("user_floorplane_id") && s.Fields.GetValue("user_floorplane_id", -1) == svg.Id) + { + if (svg.Height != s.FloorHeight) + { + int diff = s.FloorHeight - svg.Height; + + if (!newheights.ContainsKey(diff)) + newheights.Add(diff, new List() { s }); + else + newheights[diff].Add(s); + + update = true; + //break; + } + } + } + + if ((svg.SectorPlanes[s] & PlaneType.Ceiling) == PlaneType.Ceiling) + { + if (s.Fields.ContainsKey("user_ceilingplane_id") && s.Fields.GetValue("user_ceilingplane_id", -1) == svg.Id) + { + if (svg.Height != s.CeilHeight) + { + int diff = s.CeilHeight - svg.Height; + + if (!newheights.ContainsKey(diff)) + newheights.Add(diff, new List() { s }); + else + newheights[diff].Add(s); + + update = true; + //break; + } + } + } + } + + // Debug.WriteLine(String.Format("floordiff: {0} / ceilingdiff: {1} / height: {2}", floordiff, ceilingdiff, svg.Height)); + + if (update) + { + if (newheights.Count > 1) + Debug.WriteLine(String.Format("Slope: multiple new heights, doing nothing. Your map is fucked!")); + else if (!updatesvgs.ContainsKey(svg)) + updatesvgs.Add(svg, newheights.First().Key); + } + } + + // Update the slopes, and also update the view if in visual mode + foreach (SlopeVertexGroup svg in updatesvgs.Keys) + { + foreach (SlopeVertex sv in svg.Vertices) + sv.Z += updatesvgs[svg]; + + svg.ComputeHeight(); + + foreach (Sector s in svg.Sectors) + UpdateSlopes(s); + + // Save the updated data in the sector + svg.StoreInSector(slopedatasector); + + if (General.Editing.Mode is BaseVisualMode) + { + List sectors = new List(); + List visualsectors = new List(); + BaseVisualMode mode = ((BaseVisualMode)General.Editing.Mode); + + foreach (Sector s in svg.Sectors) + { + sectors.Add(s); + + // Get neighbouring sectors and add them to the list + foreach (Sidedef sd in s.Sidedefs) + { + if (sd.Other != null && !sectors.Contains(sd.Other.Sector)) + sectors.Add(sd.Other.Sector); + } + } + + foreach (Sector s in svg.TaggedSectors) + { + if(!sectors.Contains(s)) + sectors.Add(s); + + // Get neighbouring sectors and add them to the list + foreach (Sidedef sd in s.Sidedefs) + { + if (sd.Other != null && !sectors.Contains(sd.Other.Sector)) + sectors.Add(sd.Other.Sector); + } + } + + foreach (Sector s in sectors) + visualsectors.Add(mode.GetVisualSector(s)); + + foreach (VisualSector vs in visualsectors) vs.UpdateSectorGeometry(true); + foreach (VisualSector vs in visualsectors) vs.UpdateSectorData(); + } + } + } + + public override bool OnModeChange(EditMode oldmode, EditMode newmode) + { + if (newmode != null && oldmode != null) + { + if (newmode.GetType().Name == "DragSectorsMode") + { + foreach (SlopeVertexGroup svg in slopevertexgroups) + if (svg.Reposition) + svg.GetAnchor(); + } + else if(oldmode.GetType().Name == "DragSectorsMode") + { + foreach (SlopeVertexGroup svg in slopevertexgroups) + if (svg.Reposition) + { + svg.RepositionByAnchor(); + svg.StoreInSector(slopedatasector); + } + } + + } + + return base.OnModeChange(oldmode, newmode); + } + + // When the Preferences dialog is shown + public override void OnShowPreferences(PreferencesController controller) + { + base.OnShowPreferences(controller); + + // Load preferences + preferencesform = new PreferencesForm(); + preferencesform.Setup(controller); + } + + // When the Preferences dialog is closed + public override void OnClosePreferences(PreferencesController controller) + { + base.OnClosePreferences(controller); + + // Apply settings that could have been changed + LoadSettings(); + + // Unload preferences + preferencesform.Dispose(); + preferencesform = null; + } + + #region ================== Actions + + #endregion + + #region ================== Methods + + private Sector GetSlopeDataSector() + { + foreach (Sector s in General.Map.Map.Sectors) + { + if (s.Fields.GetValue("user_slopedatasector", false) == true) + return s; + } + + return null; + } + + public DialogResult ThreeDFloorEditor() + { + List selectedSectors = new List(General.Map.Map.GetSelectedSectors(true)); + + if (selectedSectors.Count <= 0 && General.Editing.Mode.HighlightedObject is Sector) + selectedSectors.Add((Sector)General.Editing.Mode.HighlightedObject); + + if (tdfew == null) + tdfew = new ThreeDFloorEditorWindow(); + + tdfew.ThreeDFloors = GetThreeDFloors(selectedSectors); + DialogResult result = tdfew.ShowDialog((Form)General.Interface); + + return result; + } + + // Use the same settings as the BuilderModes plugin + private void LoadSettings() + { + additiveselect = General.Settings.ReadPluginSetting("BuilderModes", "additiveselect", false); + autoclearselection = General.Settings.ReadPluginSetting("BuilderModes", "autoclearselection", false); + highlightsloperange = (float)General.Settings.ReadPluginSetting("BuilderModes", "highlightthingsrange", 10); + stitchrange = (float)General.Settings.ReadPluginSetting("BuilderModes", "stitchrange", 20); + slopevertexlabeldisplayoption = (LabelDisplayOption)General.Settings.ReadPluginSetting("slopevertexlabeldisplayoption", (int)LabelDisplayOption.Always); + sectorlabeldisplayoption = (LabelDisplayOption)General.Settings.ReadPluginSetting("sectorlabeldisplayoption", (int)LabelDisplayOption.Always); + } + + public void StoreSlopeVertexGroupsInSector() + { + if (slopedatasector != null && !slopedatasector.IsDisposed) + { + slopedatasector.Fields.BeforeFieldsChange(); + + if (!slopedatasector.Fields.ContainsKey("user_slopedatasector")) + { + slopedatasector.Fields.Add("user_slopedatasector", new UniValue(UniversalType.Boolean, true)); + } + + slopedatasector.Fields["comment"] = new UniValue(UniversalType.String, "[!]DO NOT EDIT OR DELETE! This sector is used by the slope mode for undo/redo operations."); + + foreach (SlopeVertexGroup svg in slopevertexgroups) + svg.StoreInSector(slopedatasector); + } + } + + public void LoadSlopeVertexGroupsFromSector() + { + Regex svgregex = new Regex(@"user_svg(\d+)_v0_x", RegexOptions.IgnoreCase); + + slopevertexgroups.Clear(); + + if (slopedatasector == null || slopedatasector.IsDisposed) + return; + + foreach (KeyValuePair kvp in slopedatasector.Fields) + { + Match svgmatch = svgregex.Match((string)kvp.Key); + + if (svgmatch.Success) + { + int svgid = Convert.ToInt32(svgmatch.Groups[1].ToString()); + + slopevertexgroups.Add(new SlopeVertexGroup(svgid, slopedatasector)); + } + } + + General.Map.Map.Update(); + } + + public void UpdateSlopes() + { + // foreach (Sector s in General.Map.Map.Sectors) + // UpdateSlopes(s); + + foreach (SlopeVertexGroup svg in slopevertexgroups) + { + foreach (Sector s in svg.Sectors) + { + if (s != null && !s.IsDisposed) + UpdateSlopes(s); + } + } + } + + public Vector3D CRS(Vector3D p0, Vector3D p1, Vector3D p2, Vector3D p3, float t) + { + return 0.5f * ((2 * p1) + + (-p0 + p2) * t + + (2 * p0 - 5 * p1 + 4 * p2 - p3) * (t * t) + + (-p0 + 3 * p1 - 3 * p2 + p3) * (t * t * t) + ); + } + + public void UpdateSlopes(Sector s) + { + string[] fieldnames = new string[] { "user_floorplane_id", "user_ceilingplane_id" }; + + foreach (string fn in fieldnames) + { + int id = s.Fields.GetValue(fn, -1); + + if (id == -1) + { + if (fn == "user_floorplane_id") + { + s.FloorSlope = new Vector3D(); + s.FloorSlopeOffset = 0; + } + else + { + s.CeilSlope = new Vector3D(); + s.CeilSlopeOffset = 0; + } + + continue; + } + + List sp = new List(); + SlopeVertexGroup svg = GetSlopeVertexGroup(id); + + // If the SVG does not exist unbind the SVG info from this sector + if (svg == null) + { + s.Fields.Remove(fn); + continue; + } + + if (svg.Spline) + { + Vector2D center = new Vector2D(s.BBox.Width / 2 + s.BBox.X, s.BBox.Height / 2 + s.BBox.Y); + List splinelines = new List(); + List tangents = new List(); + + sp.Add(new Vector3D(svg.Vertices[1].Pos.x, svg.Vertices[1].Pos.y, svg.Vertices[1].Z)); + sp.Add(new Vector3D(svg.Vertices[0].Pos.x, svg.Vertices[0].Pos.y, svg.Vertices[0].Z)); + sp.Add(new Vector3D(svg.Vertices[2].Pos.x, svg.Vertices[2].Pos.y, svg.Vertices[2].Z)); + + sp.Add(new Vector3D(sp[2].x-96, sp[2].y, sp[2].z-64)); + sp.Insert(0, new Vector3D(sp[0].x+96, sp[0].y, sp[0].z-64)); + //sp.Add(new Vector3D(sp[2] + (sp[2] - sp[1]))); + //sp.Insert(0, new Vector3D(sp[0] + (sp[0] - sp[1]))); + + + // Create tangents + tangents.Add(new Vector3D()); + + for (int i = 1; i <= 3; i++) + tangents.Add(new Vector3D((sp[i + 1] - sp[i - 1]) / 2.0f)); + + tangents.Add(new Vector3D()); + + Debug.Print("----- tangents -----"); + for (int i = 0; i < tangents.Count; i++) + Debug.Print(tangents[i].ToString()); + + for(float u=0.0f; u < 1.0f; u += 0.1f) + { + splinelines.Add(new Line3D( + CRS(sp[0], sp[1], sp[2], sp[3], u), + CRS(sp[0], sp[1], sp[2], sp[3], u+0.1f) + )); + /* + splinelines.Add(new Line3D( + Tools.HermiteSpline(sp[1], tangents[1], sp[2], tangents[2], u), + Tools.HermiteSpline(sp[1], tangents[1], sp[2], tangents[2], u+0.1f) + ) + ); + */ + } + + for (float u = 0.0f; u < 1.0f; u += 0.1f) + { + splinelines.Add(new Line3D( + CRS(sp[1], sp[2], sp[3], sp[4], u), + CRS(sp[1], sp[2], sp[3], sp[4], u + 0.1f) + )); + /* + splinelines.Add(new Line3D( + Tools.HermiteSpline(sp[2], tangents[2], sp[3], tangents[3], u), + Tools.HermiteSpline(sp[2], tangents[2], sp[3], tangents[3], u + 0.1f) + ) + ); + */ + } + + drawlines.Clear(); + drawlines.AddRange(splinelines); + + drawpoints.Clear(); + drawpoints.AddRange(sp); + + Line2D sl1 = new Line2D(sp[1], sp[2]); + Line2D sl2 = new Line2D(sp[2], sp[3]); + List points = new List(); + + Debug.Print("----- spline lines -----"); + foreach(Line3D l in splinelines) + Debug.Print(l.Start.ToString() + " / " + l.End.ToString()); + + foreach (Sidedef sd in s.Sidedefs) + { + float u = 0.0f; + Plane ldplane = new Plane(sd.Line.Start.Position, sd.Line.End.Position, new Vector3D(sd.Line.Start.Position.x, sd.Line.Start.Position.y, 128), true); + + foreach(Line3D l in splinelines) + { + if(ldplane.GetIntersection(l.Start, l.End, ref u)) + { + if (u < 0.0f || u > 1.0f) + continue; + + Vector3D v = (l.End - l.Start) * u + l.Start; + points.Add(v); + } + } + + /* + if(sd.Line.Line.GetIntersection(sl1, out u)) + points.Add(Tools.HermiteSpline(sp[1], tangents[1], sp[2], tangents[2], u)); + + if (sd.Line.Line.GetIntersection(sl2, out u)) + points.Add(Tools.HermiteSpline(sp[2], tangents[2], sp[3], tangents[3], u)); + */ + } + + + if (fn == "user_floorplane_id") + { + /* + s.FloorSlope = new Vector3D(p.a, p.b, p.c); + s.FloorSlopeOffset = p.d; + */ + } + else + { + List ps = new List(); + + if (points.Count > 2) + points.RemoveAt(0); + + Vector2D perp = new Line2D(points[0], points[1]).GetPerpendicular(); + + ps.Add(points[0]); + ps.Add(points[1]); + ps.Add(new Vector3D(points[0].x+perp.x, points[0].y+perp.y, points[0].z)); + + Debug.Print("----- points -----"); + for (int i = 0; i < ps.Count; i++) + Debug.Print(ps[i].ToString()); + + /* + for(int i=0; i < ps.Count; i++) + { + ps[i] = new Vector3D(ps[i].x, ps[i].z, ps[i].y); + } + */ + + Debug.Print("-----"); + for (int i = 0; i < ps.Count; i++) + Debug.Print(ps[i].ToString()); + + Plane p = new Plane(ps[0], ps[1], ps[2], false); + + s.CeilSlope = new Vector3D(p.a, p.b, p.c); + s.CeilSlopeOffset = p.d; + } + + } + else // No spline + { + for (int i = 0; i < svg.Vertices.Count; i++) + { + sp.Add(new Vector3D(svg.Vertices[i].Pos.x, svg.Vertices[i].Pos.y, svg.Vertices[i].Z)); + } + + if (svg.Vertices.Count == 2) + { + float z = sp[0].z; + Line2D line = new Line2D(sp[0], sp[1]); + Vector3D perpendicular = line.GetPerpendicular(); + + Vector2D v = sp[0] + perpendicular; + + sp.Add(new Vector3D(v.x, v.y, z)); + } + + if (fn == "user_floorplane_id") + { + Plane p = new Plane(sp[0], sp[1], sp[2], true); + + s.FloorSlope = new Vector3D(p.a, p.b, p.c); + s.FloorSlopeOffset = p.d; + s.FloorHeight = svg.Height; + svg.Height = s.FloorHeight; + } + else + { + Plane p = new Plane(sp[0], sp[1], sp[2], false); + + s.CeilSlope = new Vector3D(p.a, p.b, p.c); + s.CeilSlopeOffset = p.d; + s.CeilHeight = svg.Height; + svg.Height = s.CeilHeight; + } + } + } + } + + public static List GetThreeDFloors(List sectors) + { + List tdf = new List(); + List tmpsectors = new List(); + + // Immediately return if the list is empty + if (sectors.Count == 0) + return tdf; + + foreach (Linedef ld in General.Map.Map.Linedefs) + if (ld.Action == 160) + foreach (Sector s in sectors) + if (s != null && s.Tags.Contains(ld.Args[0]) && !tmpsectors.Contains(ld.Front.Sector)) + tmpsectors.Add(ld.Front.Sector); + + foreach(Sector s in tmpsectors) + if(s != null) + tdf.Add(new ThreeDFloor(s)); + + return tdf; + } + + public static void ProcessThreeDFloors(List threedfloors) + { + ProcessThreeDFloors(threedfloors, null); + } + + public static void ProcessThreeDFloors(List threedfloors, List selectedSectors) + { + // List selectedSectors = new List(General.Map.Map.GetSelectedSectors(true)); + var sectorsByTag = new Dictionary>(); + var sectorsToThreeDFloors = new Dictionary>(); + var sectorGroups = new List>(); + List tagblacklist = new List(); + + if(selectedSectors == null) + selectedSectors = new List(General.Map.Map.GetSelectedSectors(true)); + + var tmpSelectedSectors = new List(selectedSectors); + + foreach (ThreeDFloor tdf in GetThreeDFloors(selectedSectors)) + { + bool add = true; + + foreach (ThreeDFloor tdf2 in threedfloors) + { + if (tdf.Sector == tdf2.Sector) + { + add = false; + break; + } + } + + if (add) + { + threedfloors.Add(tdf); + } + } + + tmpSelectedSectors = new List(selectedSectors); + + General.Map.UndoRedo.CreateUndo("Modify 3D floors"); + + // Create a list of all tags used by the control sectors. This is necessary so that + // tags that will be assigned to not yet existing geometry will not be used + foreach (ThreeDFloor tdf in threedfloors) + foreach (int tag in tdf.Tags) + if (!tagblacklist.Contains(tag)) + tagblacklist.Add(tag); + + try + { + foreach (ThreeDFloor tdf in threedfloors) + { + if (tdf.Rebuild) + tdf.DeleteControlSector(); + + if (tdf.IsNew || tdf.Rebuild) + tdf.CreateGeometry(tagblacklist); + + tdf.UpdateGeometry(); + } + } + catch (Exception e) + { + MessageBox.Show(e.Message + "\nPlease increase the size of the control sector area.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + General.Map.UndoRedo.WithdrawUndo(); + return; + } + + // Fill the sectorsToThreeDFloors dictionary, with a selected sector as key + // and a list of all 3D floors, that should be applied to to this sector, as value + foreach (Sector s in selectedSectors) + { + // Multiple tags is actually a UDMF field, so make sure it gets recorded for undo/redo + s.Fields.BeforeFieldsChange(); + + if (!sectorsToThreeDFloors.ContainsKey(s)) + sectorsToThreeDFloors.Add(s, new List()); + + foreach (ThreeDFloor tdf in threedfloors) + { + if (tdf.TaggedSectors.Contains(s)) + sectorsToThreeDFloors[s].Add(tdf); + } + } + + // Group all selected sectors by their 3D floors. I.e. each element of sectorGroups + // is a list of sectors that have the same 3D floors + while (tmpSelectedSectors.Count > 0) + { + Sector s1 = tmpSelectedSectors.First(); + var list = new List(); + var delsectors = new List(); + + foreach (Sector s2 in tmpSelectedSectors) + { + if (sectorsToThreeDFloors[s1].ContainsAllElements(sectorsToThreeDFloors[s2])) + { + list.Add(s2); + delsectors.Add(s2); + } + } + + foreach (Sector s in delsectors) + tmpSelectedSectors.Remove(s); + + tmpSelectedSectors.Remove(s1); + + sectorGroups.Add(list); + } + + // Bind the 3D floors to the selected sectors + foreach (List sectors in sectorGroups) + { + if (General.Map.UDMF == true) + { + foreach (Sector s in sectors) + { + // Remove all tags associated to 3D floors from the sector... + foreach (ThreeDFloor tdf in threedfloors) + { + if (s.Tags.Contains(tdf.UDMFTag)) + s.Tags.Remove(tdf.UDMFTag); + } + + // ... and re-add the ones that are still associated + foreach (ThreeDFloor tdf in sectorsToThreeDFloors[s]) + { + if (!s.Tags.Contains(tdf.UDMFTag)) + s.Tags.Add(tdf.UDMFTag); + } + + // Remove tag 0 if there are other tags present, or add tag 0 if the sector has no tags + if (s.Tags.Count > 1 && s.Tags.Contains(0)) + s.Tags.Remove(0); + + if(s.Tags.Count == 0) + s.Tags.Add(0); + + } + } + else + { + int newtag; + + // Just use sectors.First(), all elements in sectors have the same 3D floors anyway + // If there are no 3D floors associated set the tag to 0 + if (sectorsToThreeDFloors[sectors.First()].Count == 0) + newtag = 0; + else + try + { + newtag = BuilderPlug.Me.ControlSectorArea.GetNewSectorTag(tagblacklist); + } + catch (Exception e) + { + MessageBox.Show(e.Message + "\nPlease increase the custom tag range.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + General.Map.UndoRedo.WithdrawUndo(); + return; + } + + + foreach (Sector s in sectors) + s.Tag = newtag; + + try + { + foreach (ThreeDFloor tdf in sectorsToThreeDFloors[sectors.First()]) + tdf.BindTag(newtag); + } + catch (Exception e) + { + MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + General.Map.UndoRedo.WithdrawUndo(); + return; + } + } + } + + // Remove unused tags from the 3D floors + foreach (ThreeDFloor tdf in threedfloors) + tdf.Cleanup(); + } + + public SlopeVertexGroup AddSlopeVertexGroup(List vertices, out int id) + { + for (int i = 1; i < int.MaxValue; i++) + { + if (!slopevertexgroups.Exists(x => x.Id == i)) + { + SlopeVertexGroup svg = new SlopeVertexGroup(i, (List)vertices); + + slopevertexgroups.Add(svg); + + id = i; + + return svg; + } + } + + throw new Exception("No free slope vertex group ids"); + } + + public SlopeVertexGroup GetSlopeVertexGroup(SlopeVertex sv) + { + foreach (SlopeVertexGroup svg in slopevertexgroups) + { + if (svg.Vertices.Contains(sv)) + return svg; + } + + return null; + } + + public SlopeVertexGroup GetSlopeVertexGroup(int id) + { + foreach (SlopeVertexGroup svg in slopevertexgroups) + { + if (svg.Id == id) + return svg; + } + + return null; + } + + public SlopeVertexGroup GetSlopeVertexGroup(Sector s) + { + foreach (SlopeVertexGroup svg in slopevertexgroups) + { + if (svg.Sectors.Contains(s)) + return svg; + } + + return null; + } + + #endregion + } + + public static class ThreeDFloorHelpers + { + public static List GetSectorsByTag(this MapSet ms, int tag) + { + List sectors = new List(); + + foreach (Sector s in ms.Sectors) + if (s.Tags.Contains(tag)) + sectors.Add(s); + + return sectors; + } + + public static bool ContainsAllElements(this List list1, List list2) + { + if (list1.Count != list2.Count) + return false; + + foreach (T i in list1) + if (!list2.Contains(i)) + return false; + + return true; + } + + // Taken from http://stackoverflow.com/questions/10816803/finding-next-available-key-in-a-dictionary-or-related-collection + // Add item to sortedList (numeric key) to next available key item, and return key + public static int AddNext(this SortedList sortedList, T item) + { + int key = 1; // Make it 0 to start from Zero based index + int count = sortedList.Count; + + int counter = 0; + do + { + if (count == 0) break; + int nextKeyInList = sortedList.Keys[counter++]; + + if (key != nextKeyInList) break; + + key = nextKeyInList + 1; + + if (count == 1 || counter == count) break; + + + if (key != sortedList.Keys[counter]) + break; + + } while (true); + + sortedList.Add(key, item); + return key; + } + } +} diff --git a/Source/Plugins/3DFloorMode/ControlSectorArea.cs b/Source/Plugins/3DFloorMode/ControlSectorArea.cs new file mode 100644 index 00000000..d3193bc8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/ControlSectorArea.cs @@ -0,0 +1,541 @@ +#region ================== Copyright (c) 2014 Boris Iwanski + +/* + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +using System; +using System.Windows.Forms; +using System.Collections; +using System.Collections.Specialized; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Diagnostics; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Map; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class ControlSectorArea + { + + #region ================== Enums + + public enum Highlight + { + None, + OuterLeft, + OuterRight, + OuterTop, + OuterBottom, + OuterTopLeft, + OuterTopRight, + OuterBottomLeft, + OuterBottomRight, + Body + }; + + #endregion + + #region ================== Variables + + private RectangleF outerborder; + private PixelColor bordercolor = new PixelColor(255, 0, 192, 0); + private PixelColor fillcolor = new PixelColor(128, 0, 128, 0); + private PixelColor borderhighlightcolor = new PixelColor(255, 0, 192, 0); + private PixelColor fillhighlightcolor = new PixelColor(128, 0, 192, 0); + private Dictionary lines; + private Dictionary points; + private float gridsize; + private float gridsizeinv; + private float sectorsize; + + private float outerleft; + private float outerright; + private float outertop; + private float outerbottom; + + private bool usecustomtagrange; + private int firsttag; + private int lasttag; + + #endregion + + #region ================== Properties + + public float GridSize { get { return gridsize; } } + public float SectorSize { get { return sectorsize; } } + + public RectangleF OuterBorder { get { return outerborder; } } + + public float OuterLeft + { + get { return outerleft; } + set { outerleft = value; UpdateLinesAndPoints(); } + } + + public float OuterRight + { + get { return outerright; } + set { outerright = value; UpdateLinesAndPoints(); } + } + + public float OuterTop + { + get { return outertop; } + set { outertop = value; UpdateLinesAndPoints(); } + } + + public float OuterBottom + { + get { return outerbottom; } + set { outerbottom = value; UpdateLinesAndPoints(); } + } + + public bool UseCustomTagRnage { get { return usecustomtagrange; } set { usecustomtagrange = value; } } + public int FirstTag { get { return firsttag; } set { firsttag = value; } } + public int LastTag { get { return lasttag; } set { lasttag = value; } } + + #endregion + + #region ================== Constructor / Disposer + + public ControlSectorArea(float outerleft, float outerright, float outertop, float outerbottom, float gridsize, float sectorsize) + { + this.outerleft = outerleft; + this.outerright = outerright; + this.outertop = outertop; + this.outerbottom = outerbottom; + + lines = new Dictionary(); + points = new Dictionary(); + + this.gridsize = gridsize; + gridsizeinv = 1.0f / gridsize; + + this.sectorsize = sectorsize; + + UpdateLinesAndPoints(); + } + + #endregion + + #region ================== Methods + + public void UpdateLinesAndPoints() + { + lines[Highlight.OuterLeft] = new Line2D(outerleft, outertop, outerleft, outerbottom); + lines[Highlight.OuterRight] = new Line2D(outerright, outertop, outerright, outerbottom); + lines[Highlight.OuterTop] = new Line2D(outerleft, outertop, outerright, outertop); + lines[Highlight.OuterBottom] = new Line2D(outerleft, outerbottom, outerright, outerbottom); + + points[Highlight.OuterTopLeft] = new Vector2D(outerleft, outertop); + points[Highlight.OuterTopRight] = new Vector2D(outerright, outertop); + points[Highlight.OuterBottomLeft] = new Vector2D(outerleft, outerbottom); + points[Highlight.OuterBottomRight] = new Vector2D(outerright, outerbottom); + + outerborder = new RectangleF(outerleft, outertop, outerright - outerleft, outerbottom - outertop); + } + + public void Draw(IRenderer2D renderer, Highlight highlight) + { + PixelColor fcolor = highlight == Highlight.Body ? fillhighlightcolor : fillcolor; + + renderer.RenderRectangleFilled( + new RectangleF(outerleft, outertop, outerright - outerleft, outerbottom - outertop), + fcolor, + true + ); + + // Draw the borders + renderer.RenderRectangle(outerborder, 1.0f, bordercolor, true); + + // Highlight a border if necessary + if (highlight >= Highlight.OuterLeft && highlight <= Highlight.OuterBottom) + renderer.RenderLine(lines[highlight].v1, lines[highlight].v2, 1.0f, borderhighlightcolor, true); + else + { + // Highlight the corners + switch (highlight) + { + // Outer corners + case Highlight.OuterTopLeft: + renderer.RenderLine(lines[Highlight.OuterTop].v1, lines[Highlight.OuterTop].v2, 1.0f, borderhighlightcolor, true); + renderer.RenderLine(lines[Highlight.OuterLeft].v1, lines[Highlight.OuterLeft].v2, 1.0f, borderhighlightcolor, true); + break; + case Highlight.OuterTopRight: + renderer.RenderLine(lines[Highlight.OuterTop].v1, lines[Highlight.OuterTop].v2, 1.0f, borderhighlightcolor, true); + renderer.RenderLine(lines[Highlight.OuterRight].v1, lines[Highlight.OuterRight].v2, 1.0f, borderhighlightcolor, true); + break; + case Highlight.OuterBottomLeft: + renderer.RenderLine(lines[Highlight.OuterBottom].v1, lines[Highlight.OuterBottom].v2, 1.0f, borderhighlightcolor, true); + renderer.RenderLine(lines[Highlight.OuterLeft].v1, lines[Highlight.OuterLeft].v2, 1.0f, borderhighlightcolor, true); + break; + case Highlight.OuterBottomRight: + renderer.RenderLine(lines[Highlight.OuterBottom].v1, lines[Highlight.OuterBottom].v2, 1.0f, borderhighlightcolor, true); + renderer.RenderLine(lines[Highlight.OuterRight].v1, lines[Highlight.OuterRight].v2, 1.0f, borderhighlightcolor, true); + break; + } + } + } + + public Highlight CheckHighlight(Vector2D pos, float scale) + { + float distance = float.MaxValue; + float d; + Highlight highlight = Highlight.None; + + // Find a line to highlight + foreach (Highlight h in (Highlight[])Enum.GetValues(typeof(Highlight))) + { + if (h >= Highlight.OuterLeft && h <= Highlight.OuterBottom) + { + d = Line2D.GetDistanceToLine(lines[h].v1, lines[h].v2, pos, true); + + if (d <= BuilderModes.BuilderPlug.Me.HighlightRange / scale && d < distance) + { + distance = d; + highlight = h; + } + } + } + + distance = float.MaxValue; + + // Find a corner to highlight + foreach (Highlight h in (Highlight[])Enum.GetValues(typeof(Highlight))) + { + if (h >= Highlight.OuterTopLeft && h <= Highlight.OuterBottomRight) + { + d = Vector2D.Distance(pos, points[h]); + + if (d <= BuilderModes.BuilderPlug.Me.HighlightRange / scale && d < distance) + { + distance = d; + highlight = h; + } + } + } + + if (highlight != Highlight.None) + return highlight; + + if (OuterLeft < pos.x && OuterRight > pos.x && OuterTop > pos.y && OuterBottom < pos.y) + return Highlight.Body; + + return Highlight.None; + } + + public void SnapToGrid(Highlight highlight, Vector2D pos, Vector2D lastpos) + { + Vector2D newpos = GridSetup.SnappedToGrid(pos, gridsize, gridsizeinv); + + switch (highlight) + { + case Highlight.Body: + Vector2D diff = GridSetup.SnappedToGrid(pos, gridsize, gridsizeinv) - GridSetup.SnappedToGrid(lastpos, gridsize, gridsizeinv); + Debug.WriteLine("diff: " + (diff).ToString()); + outerleft += diff.x; + outerright += diff.x; + outertop += diff.y; + outerbottom += diff.y; + break; + + // Outer border + case Highlight.OuterLeft: + if (newpos.x < outerright) outerleft = newpos.x; + break; + case Highlight.OuterRight: + if(newpos.x > outerleft) outerright = newpos.x; + break; + case Highlight.OuterTop: + if (newpos.y > outerbottom) outertop = newpos.y; + break; + case Highlight.OuterBottom: + if (newpos.y < outertop) outerbottom = newpos.y; + break; + + // Outer corners + case Highlight.OuterTopLeft: + if (newpos.x < outerright) outerleft = newpos.x; + if (newpos.y > outerbottom) outertop = newpos.y; + break; + case Highlight.OuterTopRight: + if (newpos.x > outerleft) outerright = newpos.x; + if (newpos.y > outerbottom) outertop = newpos.y; + break; + case Highlight.OuterBottomLeft: + if (newpos.x < outerright) outerleft = newpos.x; + if (newpos.y < outertop) outerbottom = newpos.y; + break; + case Highlight.OuterBottomRight: + if (newpos.x > outerleft) outerright = newpos.x; + if (newpos.y < outertop) outerbottom = newpos.y; + break; + } + + UpdateLinesAndPoints(); + } + + public List GetRelocatePositions(int numsectors) + { + List positions = new List(); + BlockMap blockmap = CreateBlockmap(true); + int margin = (int)((gridsize - sectorsize) / 2); + + for (int x = (int)outerleft; x < (int)outerright; x += (int)gridsize) + { + for (int y = (int)outertop; y > (int)outerbottom; y -= (int)gridsize) + { + List blocks = blockmap.GetLineBlocks( + new Vector2D(x + 1, y - 1), + new Vector2D(x + gridsize - 1, y - gridsize + 1) + ); + + // The way our blockmap is built and queried we will always get exactly one block + if (blocks[0].Sectors.Count == 0) + { + positions.Add(new Vector2D(x + margin, y - margin)); + numsectors--; + } + + if (numsectors == 0) + return positions; + } + } + + throw new Exception("Not enough space for control sector relocation"); + } + + public List GetNewControlSectorVertices() + { + BlockMap blockmap = CreateBlockmap(); + + int margin = (int)((gridsize - sectorsize) / 2); + + // find position for new control sector + for (int x = (int)outerleft; x < (int)outerright; x += (int)gridsize) + { + for (int y = (int)outertop; y > (int)outerbottom; y -= (int)gridsize) + { + List blocks = blockmap.GetLineBlocks( + new Vector2D(x + 1, y - 1), + new Vector2D(x + gridsize - 1, y - gridsize + 1) + ); + + // The way our blockmap is built and queried we will always get exactly one block + if (blocks[0].Sectors.Count == 0) + { + List dv = new List(); + Point p = new Point(x + margin, y - margin); + + dv.Add(SectorVertex(p.X, p.Y)); + dv.Add(SectorVertex(p.X + BuilderPlug.Me.ControlSectorArea.SectorSize, p.Y)); + dv.Add(SectorVertex(p.X + BuilderPlug.Me.ControlSectorArea.SectorSize, p.Y - BuilderPlug.Me.ControlSectorArea.SectorSize)); + dv.Add(SectorVertex(p.X, p.Y - BuilderPlug.Me.ControlSectorArea.SectorSize)); + dv.Add(SectorVertex(p.X, p.Y)); + + return dv; + } + } + } + + throw new Exception("No space left for control sectors"); + } + + public bool Inside(float x, float y) + { + return Inside(new Vector2D(x, y)); + } + + public bool Inside(Vector2D pos) + { + if (pos.x > outerleft && pos.x < outerright && pos.y < outertop && pos.y > outerbottom) + return true; + + return false; + } + + public bool OutsideOuterBounds(float x, float y) + { + return OutsideOuterBounds(new Vector2D(x, y)); + } + + public bool OutsideOuterBounds(Vector2D pos) + { + if(pos.x < outerleft || pos.x > outerright || pos.y > outertop || pos.y < outerbottom) + return true; + + return false; + } + + // Aligns the area to the grid, expanding the area if necessary + private RectangleF AlignAreaToGrid(RectangleF area) + { + List f = new List + { + area.Left, + area.Top, + area.Right, + area.Bottom + }; + + for (int i = 0; i < f.Count; i++) + { + if (f[i] < 0) + f[i] = (float)Math.Floor(f[i] / gridsize) * gridsize; + else + f[i] = (float)Math.Ceiling(f[i] / gridsize) * gridsize; + } + + + float l = f[0]; + float t = f[1]; + float r = f[2]; + float b = f[3]; + + return new RectangleF(l, t, r - l, b - t); + } + + private BlockMap CreateBlockmap() + { + return CreateBlockmap(false); + } + + private BlockMap CreateBlockmap(bool ignorecontrolsectors) + { + // Make blockmap + RectangleF area = MapSet.CreateArea(General.Map.Map.Vertices); + area = MapSet.IncreaseArea(area, new Vector2D(outerleft, outertop)); + area = MapSet.IncreaseArea(area, new Vector2D(outerright, outerbottom)); + area = AlignAreaToGrid(area); + + BlockMap blockmap = new BlockMap(area, (int)gridsize); + + if (ignorecontrolsectors) + { + foreach (Sector s in General.Map.Map.Sectors) + { + // Managed control sectors have the custom UDMF field "user_managed_3d_floor" set to true + // So if the field is NOT set, add the sector to the blockmap + if (s.Fields.GetValue("user_managed_3d_floor", false) == false) + blockmap.AddSector(s); + } + } + else + { + blockmap.AddSectorsSet(General.Map.Map.Sectors); + } + + return blockmap; + } + + public void Edit() + { + ControlSectorAreaConfig csacfg = new ControlSectorAreaConfig(this); + + csacfg.ShowDialog((Form)General.Interface); + } + + public void SaveConfig() + { + ListDictionary config = new ListDictionary(); + + config.Add("usecustomtagrange", usecustomtagrange); + + if (usecustomtagrange) + { + config.Add("firsttag", firsttag); + config.Add("lasttag", lasttag); + } + + config.Add("outerleft", outerleft); + config.Add("outerright", outerright); + config.Add("outertop", outertop); + config.Add("outerbottom", outerbottom); + + General.Map.Options.WritePluginSetting("controlsectorarea", config); + } + + public void LoadConfig() + { + ListDictionary config = (ListDictionary)General.Map.Options.ReadPluginSetting("controlsectorarea", new ListDictionary()); + + usecustomtagrange = General.Map.Options.ReadPluginSetting("controlsectorarea.usecustomtagrange", false); + firsttag = General.Map.Options.ReadPluginSetting("controlsectorarea.firsttag", 0); + lasttag = General.Map.Options.ReadPluginSetting("controlsectorarea.lasttag", 0); + + outerleft = General.Map.Options.ReadPluginSetting("controlsectorarea.outerleft", outerleft); + outerright = General.Map.Options.ReadPluginSetting("controlsectorarea.outerright", outerright); + outertop = General.Map.Options.ReadPluginSetting("controlsectorarea.outertop", outertop); + outerbottom = General.Map.Options.ReadPluginSetting("controlsectorarea.outerbottom", outerbottom); + + UpdateLinesAndPoints(); + } + + public int GetNewSectorTag(List tagblacklist) + { + List usedtags = new List(); + + if (usecustomtagrange) + { + for (int i = firsttag; i <= lasttag; i++) + { + if (!tagblacklist.Contains(i) && General.Map.Map.GetSectorsByTag(i).Count == 0) + return i; + } + + throw new Exception("No free tags in the custom range between " + firsttag.ToString() + " and " + lasttag.ToString() + "."); + } + + return General.Map.Map.GetNewTag(tagblacklist); + } + + public int GetNewLineID() + { + return General.Map.Map.GetNewTag(); + } + + // Turns a position into a DrawnVertex and returns it + private DrawnVertex SectorVertex(float x, float y) + { + DrawnVertex v = new DrawnVertex(); + + v.stitch = true; + v.stitchline = true; + v.pos = new Vector2D((float)Math.Round(x, General.Map.FormatInterface.VertexDecimals), (float)Math.Round(y, General.Map.FormatInterface.VertexDecimals)); + + return v; + } + + private DrawnVertex SectorVertex(Vector2D v) + { + return SectorVertex(v.x, v.y); + } + + static int GCD(int[] numbers) + { + return numbers.Aggregate(GCD); + } + + static int GCD(int a, int b) + { + return b == 0 ? a : GCD(b, a % b); + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.Designer.cs b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.Designer.cs new file mode 100644 index 00000000..01e337fc --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.Designer.cs @@ -0,0 +1,421 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ThreeDFloorHelperControl + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Komponenten-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.sectorTopFlat = new CodeImp.DoomBuilder.Controls.FlatSelectorControl(); + this.sectorBorderTexture = new CodeImp.DoomBuilder.Controls.TextureSelectorControl(); + this.sectorBottomFlat = new CodeImp.DoomBuilder.Controls.FlatSelectorControl(); + this.sectorCeilingHeight = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.sectorFloorHeight = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.checkedListBoxSectors = new System.Windows.Forms.CheckedListBox(); + this.buttonDuplicate = new System.Windows.Forms.Button(); + this.buttonSplit = new System.Windows.Forms.Button(); + this.buttonCheckAll = new System.Windows.Forms.Button(); + this.buttonUncheckAll = new System.Windows.Forms.Button(); + this.borderHeightLabel = new System.Windows.Forms.Label(); + this.typeArgument = new CodeImp.DoomBuilder.Controls.ArgumentBox(); + this.flagsArgument = new CodeImp.DoomBuilder.Controls.ArgumentBox(); + this.buttonEditSector = new System.Windows.Forms.Button(); + this.label6 = new System.Windows.Forms.Label(); + this.alphaArgument = new CodeImp.DoomBuilder.Controls.ArgumentBox(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.sectorBrightness = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.tagsLabel = new System.Windows.Forms.Label(); + this.buttonDetach = new System.Windows.Forms.Button(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // sectorTopFlat + // + this.sectorTopFlat.Location = new System.Drawing.Point(10, 30); + this.sectorTopFlat.MultipleTextures = false; + this.sectorTopFlat.Name = "sectorTopFlat"; + this.sectorTopFlat.Size = new System.Drawing.Size(115, 136); + this.sectorTopFlat.TabIndex = 4; + this.sectorTopFlat.TextureName = ""; + // + // sectorBorderTexture + // + this.sectorBorderTexture.Location = new System.Drawing.Point(131, 30); + this.sectorBorderTexture.MultipleTextures = false; + this.sectorBorderTexture.Name = "sectorBorderTexture"; + this.sectorBorderTexture.Required = false; + this.sectorBorderTexture.Size = new System.Drawing.Size(115, 136); + this.sectorBorderTexture.TabIndex = 3; + this.sectorBorderTexture.TextureName = ""; + // + // sectorBottomFlat + // + this.sectorBottomFlat.Location = new System.Drawing.Point(252, 30); + this.sectorBottomFlat.MultipleTextures = false; + this.sectorBottomFlat.Name = "sectorBottomFlat"; + this.sectorBottomFlat.Size = new System.Drawing.Size(115, 136); + this.sectorBottomFlat.TabIndex = 2; + this.sectorBottomFlat.TextureName = ""; + // + // sectorCeilingHeight + // + this.sectorCeilingHeight.AllowDecimal = false; + this.sectorCeilingHeight.AllowExpressions = false; + this.sectorCeilingHeight.AllowNegative = true; + this.sectorCeilingHeight.AllowRelative = true; + this.sectorCeilingHeight.BackColor = System.Drawing.Color.Transparent; + this.sectorCeilingHeight.ButtonStep = 8; + this.sectorCeilingHeight.ButtonStepBig = 10F; + this.sectorCeilingHeight.ButtonStepFloat = 1F; + this.sectorCeilingHeight.ButtonStepSmall = 0.1F; + this.sectorCeilingHeight.ButtonStepsUseModifierKeys = false; + this.sectorCeilingHeight.ButtonStepsWrapAround = false; + this.sectorCeilingHeight.Location = new System.Drawing.Point(55, 0); + this.sectorCeilingHeight.Name = "sectorCeilingHeight"; + this.sectorCeilingHeight.Size = new System.Drawing.Size(70, 24); + this.sectorCeilingHeight.StepValues = null; + this.sectorCeilingHeight.TabIndex = 1; + this.sectorCeilingHeight.WhenTextChanged += new System.EventHandler(this.RecomputeBorderHeight); + // + // sectorFloorHeight + // + this.sectorFloorHeight.AllowDecimal = false; + this.sectorFloorHeight.AllowExpressions = false; + this.sectorFloorHeight.AllowNegative = true; + this.sectorFloorHeight.AllowRelative = true; + this.sectorFloorHeight.BackColor = System.Drawing.Color.Transparent; + this.sectorFloorHeight.ButtonStep = 8; + this.sectorFloorHeight.ButtonStepBig = 10F; + this.sectorFloorHeight.ButtonStepFloat = 1F; + this.sectorFloorHeight.ButtonStepSmall = 0.1F; + this.sectorFloorHeight.ButtonStepsUseModifierKeys = false; + this.sectorFloorHeight.ButtonStepsWrapAround = false; + this.sectorFloorHeight.Location = new System.Drawing.Point(297, 0); + this.sectorFloorHeight.Name = "sectorFloorHeight"; + this.sectorFloorHeight.Size = new System.Drawing.Size(70, 24); + this.sectorFloorHeight.StepValues = null; + this.sectorFloorHeight.TabIndex = 0; + this.sectorFloorHeight.WhenTextChanged += new System.EventHandler(this.RecomputeBorderHeight); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.BackColor = System.Drawing.Color.Transparent; + this.label1.Location = new System.Drawing.Point(7, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(26, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Top"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.BackColor = System.Drawing.Color.Transparent; + this.label2.Location = new System.Drawing.Point(251, 5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(40, 13); + this.label2.TabIndex = 6; + this.label2.Text = "Bottom"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.BackColor = System.Drawing.Color.Transparent; + this.label3.Location = new System.Drawing.Point(131, 5); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(38, 13); + this.label3.TabIndex = 7; + this.label3.Text = "Border"; + // + // groupBox2 + // + this.groupBox2.BackColor = System.Drawing.Color.Transparent; + this.groupBox2.Controls.Add(this.checkedListBoxSectors); + this.groupBox2.Location = new System.Drawing.Point(503, 0); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(124, 166); + this.groupBox2.TabIndex = 6; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Sectors"; + // + // checkedListBoxSectors + // + this.checkedListBoxSectors.CheckOnClick = true; + this.checkedListBoxSectors.FormattingEnabled = true; + this.checkedListBoxSectors.Location = new System.Drawing.Point(6, 19); + this.checkedListBoxSectors.Name = "checkedListBoxSectors"; + this.checkedListBoxSectors.Size = new System.Drawing.Size(110, 139); + this.checkedListBoxSectors.TabIndex = 0; + this.checkedListBoxSectors.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.checkedListBoxSectors_ItemCheck); + // + // buttonDuplicate + // + this.buttonDuplicate.Location = new System.Drawing.Point(633, 5); + this.buttonDuplicate.Name = "buttonDuplicate"; + this.buttonDuplicate.Size = new System.Drawing.Size(75, 23); + this.buttonDuplicate.TabIndex = 7; + this.buttonDuplicate.Text = "Duplicate"; + this.buttonDuplicate.UseVisualStyleBackColor = true; + this.buttonDuplicate.Click += new System.EventHandler(this.buttonDuplicate_Click); + // + // buttonSplit + // + this.buttonSplit.Location = new System.Drawing.Point(633, 34); + this.buttonSplit.Name = "buttonSplit"; + this.buttonSplit.Size = new System.Drawing.Size(75, 23); + this.buttonSplit.TabIndex = 8; + this.buttonSplit.Text = "Split"; + this.buttonSplit.UseVisualStyleBackColor = true; + this.buttonSplit.Click += new System.EventHandler(this.buttonSplit_Click); + // + // buttonCheckAll + // + this.buttonCheckAll.Location = new System.Drawing.Point(633, 92); + this.buttonCheckAll.Name = "buttonCheckAll"; + this.buttonCheckAll.Size = new System.Drawing.Size(75, 23); + this.buttonCheckAll.TabIndex = 9; + this.buttonCheckAll.Text = "Check all"; + this.buttonCheckAll.UseVisualStyleBackColor = true; + this.buttonCheckAll.Click += new System.EventHandler(this.buttonCheckAll_Click); + // + // buttonUncheckAll + // + this.buttonUncheckAll.Location = new System.Drawing.Point(633, 121); + this.buttonUncheckAll.Name = "buttonUncheckAll"; + this.buttonUncheckAll.Size = new System.Drawing.Size(75, 23); + this.buttonUncheckAll.TabIndex = 10; + this.buttonUncheckAll.Text = "Uncheck all"; + this.buttonUncheckAll.UseVisualStyleBackColor = true; + this.buttonUncheckAll.Click += new System.EventHandler(this.buttonUncheckAll_Click); + // + // borderHeightLabel + // + this.borderHeightLabel.Location = new System.Drawing.Point(196, 5); + this.borderHeightLabel.Name = "borderHeightLabel"; + this.borderHeightLabel.Size = new System.Drawing.Size(50, 13); + this.borderHeightLabel.TabIndex = 17; + this.borderHeightLabel.Text = "0"; + this.borderHeightLabel.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // typeArgument + // + this.typeArgument.BackColor = System.Drawing.Color.Transparent; + this.typeArgument.Location = new System.Drawing.Point(438, 0); + this.typeArgument.Name = "typeArgument"; + this.typeArgument.Size = new System.Drawing.Size(59, 24); + this.typeArgument.TabIndex = 18; + // + // flagsArgument + // + this.flagsArgument.BackColor = System.Drawing.Color.Transparent; + this.flagsArgument.Location = new System.Drawing.Point(438, 30); + this.flagsArgument.Name = "flagsArgument"; + this.flagsArgument.Size = new System.Drawing.Size(59, 24); + this.flagsArgument.TabIndex = 19; + // + // buttonEditSector + // + this.buttonEditSector.Location = new System.Drawing.Point(376, 143); + this.buttonEditSector.Name = "buttonEditSector"; + this.buttonEditSector.Size = new System.Drawing.Size(121, 23); + this.buttonEditSector.TabIndex = 24; + this.buttonEditSector.Text = "Edit control sector"; + this.buttonEditSector.UseVisualStyleBackColor = true; + this.buttonEditSector.Click += new System.EventHandler(this.buttonEditSector_Click); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.BackColor = System.Drawing.Color.Transparent; + this.label6.Location = new System.Drawing.Point(395, 65); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(37, 13); + this.label6.TabIndex = 23; + this.label6.Text = "Alpha:"; + // + // alphaArgument + // + this.alphaArgument.BackColor = System.Drawing.Color.Transparent; + this.alphaArgument.Location = new System.Drawing.Point(438, 60); + this.alphaArgument.Name = "alphaArgument"; + this.alphaArgument.Size = new System.Drawing.Size(59, 24); + this.alphaArgument.TabIndex = 20; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.BackColor = System.Drawing.Color.Transparent; + this.label4.Location = new System.Drawing.Point(396, 5); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(34, 13); + this.label4.TabIndex = 21; + this.label4.Text = "Type:"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.BackColor = System.Drawing.Color.Transparent; + this.label5.Location = new System.Drawing.Point(395, 35); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(35, 13); + this.label5.TabIndex = 22; + this.label5.Text = "Flags:"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.BackColor = System.Drawing.Color.Transparent; + this.label7.Location = new System.Drawing.Point(373, 95); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(59, 13); + this.label7.TabIndex = 25; + this.label7.Text = "Brightness:"; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.BackColor = System.Drawing.Color.Transparent; + this.label8.Location = new System.Drawing.Point(390, 125); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(40, 13); + this.label8.TabIndex = 26; + this.label8.Text = "Tag(s):"; + // + // sectorBrightness + // + this.sectorBrightness.AllowDecimal = false; + this.sectorBrightness.AllowExpressions = false; + this.sectorBrightness.AllowNegative = true; + this.sectorBrightness.AllowRelative = true; + this.sectorBrightness.BackColor = System.Drawing.Color.Transparent; + this.sectorBrightness.ButtonStep = 8; + this.sectorBrightness.ButtonStepBig = 10F; + this.sectorBrightness.ButtonStepFloat = 1F; + this.sectorBrightness.ButtonStepSmall = 0.1F; + this.sectorBrightness.ButtonStepsUseModifierKeys = false; + this.sectorBrightness.ButtonStepsWrapAround = false; + this.sectorBrightness.Location = new System.Drawing.Point(438, 90); + this.sectorBrightness.Name = "sectorBrightness"; + this.sectorBrightness.Size = new System.Drawing.Size(59, 24); + this.sectorBrightness.StepValues = null; + this.sectorBrightness.TabIndex = 27; + // + // tagsLabel + // + this.tagsLabel.AutoSize = true; + this.tagsLabel.Location = new System.Drawing.Point(436, 125); + this.tagsLabel.Name = "tagsLabel"; + this.tagsLabel.Size = new System.Drawing.Size(35, 13); + this.tagsLabel.TabIndex = 28; + this.tagsLabel.Text = "label9"; + // + // buttonDetach + // + this.buttonDetach.Location = new System.Drawing.Point(633, 63); + this.buttonDetach.Name = "buttonDetach"; + this.buttonDetach.Size = new System.Drawing.Size(75, 23); + this.buttonDetach.TabIndex = 29; + this.buttonDetach.Text = "Detach"; + this.buttonDetach.UseVisualStyleBackColor = true; + this.buttonDetach.Click += new System.EventHandler(this.buttonDetach_Click); + // + // ThreeDFloorHelperControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.buttonDetach); + this.Controls.Add(this.tagsLabel); + this.Controls.Add(this.sectorBrightness); + this.Controls.Add(this.label8); + this.Controls.Add(this.label7); + this.Controls.Add(this.typeArgument); + this.Controls.Add(this.flagsArgument); + this.Controls.Add(this.buttonEditSector); + this.Controls.Add(this.label6); + this.Controls.Add(this.alphaArgument); + this.Controls.Add(this.label4); + this.Controls.Add(this.label5); + this.Controls.Add(this.borderHeightLabel); + this.Controls.Add(this.buttonUncheckAll); + this.Controls.Add(this.buttonCheckAll); + this.Controls.Add(this.buttonSplit); + this.Controls.Add(this.buttonDuplicate); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.sectorFloorHeight); + this.Controls.Add(this.sectorCeilingHeight); + this.Controls.Add(this.sectorBottomFlat); + this.Controls.Add(this.sectorBorderTexture); + this.Controls.Add(this.sectorTopFlat); + this.Margin = new System.Windows.Forms.Padding(3, 3, 3, 10); + this.Name = "ThreeDFloorHelperControl"; + this.Size = new System.Drawing.Size(714, 172); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.ThreeDFloorHelperControl_Paint); + this.groupBox2.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + public CodeImp.DoomBuilder.Controls.TextureSelectorControl sectorBorderTexture; + public CodeImp.DoomBuilder.Controls.FlatSelectorControl sectorTopFlat; + public CodeImp.DoomBuilder.Controls.FlatSelectorControl sectorBottomFlat; + public CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox sectorCeilingHeight; + public CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox sectorFloorHeight; + private System.Windows.Forms.GroupBox groupBox2; + public System.Windows.Forms.CheckedListBox checkedListBoxSectors; + private System.Windows.Forms.Button buttonDuplicate; + private System.Windows.Forms.Button buttonSplit; + private System.Windows.Forms.Button buttonCheckAll; + private System.Windows.Forms.Button buttonUncheckAll; + private System.Windows.Forms.Label borderHeightLabel; + public Controls.ArgumentBox typeArgument; + public Controls.ArgumentBox flagsArgument; + private System.Windows.Forms.Button buttonEditSector; + private System.Windows.Forms.Label label6; + public Controls.ArgumentBox alphaArgument; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label label8; + public Controls.ButtonsNumericTextbox sectorBrightness; + private System.Windows.Forms.Label tagsLabel; + private System.Windows.Forms.Button buttonDetach; + } +} diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.cs b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.cs new file mode 100644 index 00000000..29c6970f --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.cs @@ -0,0 +1,347 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Text.RegularExpressions; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ThreeDFloorHelperControl : UserControl + { + private ThreeDFloor threeDFloor; + public Linedef linedef; + private bool isnew; + private Sector sector; + private List checkedsectors; + private bool used; + + public ThreeDFloor ThreeDFloor { get { return threeDFloor; } } + public bool IsNew { get { return isnew; } } + public Sector Sector { get { return sector; } } + public List CheckedSectors { get { return checkedsectors; } } + public bool Used { get { return used; } set { used = value; } } + + // Create the control from an existing linedef + public ThreeDFloorHelperControl(ThreeDFloor threeDFloor) + { + InitializeComponent(); + + Update(threeDFloor); + } + + // Create a duplicate of the given control + public ThreeDFloorHelperControl(ThreeDFloorHelperControl ctrl) : this() + { + Update(ctrl); + } + + // Create a blank control for a new 3D floor + public ThreeDFloorHelperControl() + { + InitializeComponent(); + + SetDefaults(); + } + + public void SetDefaults() + { + isnew = true; + + threeDFloor = new ThreeDFloor(); + + sectorBorderTexture.TextureName = General.Settings.DefaultTexture; + sectorTopFlat.TextureName = General.Settings.DefaultCeilingTexture; + sectorBottomFlat.TextureName = General.Settings.DefaultFloorTexture; + sectorCeilingHeight.Text = General.Settings.DefaultCeilingHeight.ToString(); + sectorFloorHeight.Text = General.Settings.DefaultFloorHeight.ToString(); + + typeArgument.Setup(General.Map.Config.LinedefActions[160].Args[1]); + flagsArgument.Setup(General.Map.Config.LinedefActions[160].Args[2]); + alphaArgument.Setup(General.Map.Config.LinedefActions[160].Args[3]); + + typeArgument.SetDefaultValue(); + flagsArgument.SetDefaultValue(); + alphaArgument.SetDefaultValue(); + + tagsLabel.Text = "0"; + + AddSectorCheckboxes(); + + for (int i = 0; i < checkedListBoxSectors.Items.Count; i++) + checkedListBoxSectors.SetItemChecked(i, true); + + //When creating a NEW 3d sector, find information about what is selected to populate the defaults + int FloorHeight = int.MinValue; + int SectorDarkest = int.MaxValue; + foreach (Sector s in BuilderPlug.TDFEW.SelectedSectors) + { + if (s.FloorHeight > FloorHeight) + FloorHeight = s.FloorHeight; + if (s.Brightness < SectorDarkest) + SectorDarkest = s.Brightness; + } + + //set the floor height to match the lowest sector selected, then offset the height by the configured default + if (FloorHeight != int.MinValue) + { + int DefaultHeight = General.Settings.DefaultCeilingHeight - General.Settings.DefaultFloorHeight; + sectorFloorHeight.Text = FloorHeight.ToString(); + sectorCeilingHeight.Text = (FloorHeight + DefaultHeight).ToString(); + } + + //set the brightness to match the darkest of all the selected sectors by default + if (SectorDarkest != int.MaxValue) { + sectorBrightness.Text = SectorDarkest.ToString(); + } else { + sectorBrightness.Text = General.Settings.DefaultBrightness.ToString(); + } + + sector = General.Map.Map.CreateSector(); + } + + public void Update(ThreeDFloorHelperControl ctrl) + { + sectorBorderTexture.TextureName = threeDFloor.BorderTexture = ctrl.threeDFloor.BorderTexture; + sectorTopFlat.TextureName = threeDFloor.TopFlat = ctrl.threeDFloor.TopFlat; + sectorBottomFlat.TextureName = threeDFloor.BottomFlat = ctrl.threeDFloor.BottomFlat; + sectorCeilingHeight.Text = ctrl.threeDFloor.TopHeight.ToString(); + sectorFloorHeight.Text = ctrl.threeDFloor.BottomHeight.ToString(); + borderHeightLabel.Text = (ctrl.threeDFloor.TopHeight - ctrl.threeDFloor.BottomHeight).ToString(); + + threeDFloor.TopHeight = ctrl.threeDFloor.TopHeight; + threeDFloor.BottomHeight = ctrl.threeDFloor.BottomHeight; + + typeArgument.SetValue(ctrl.threeDFloor.Type); + flagsArgument.SetValue(ctrl.threeDFloor.Flags); + alphaArgument.SetValue(ctrl.threeDFloor.Alpha); + sectorBrightness.Text = ctrl.threeDFloor.Brightness.ToString(); + + for (int i = 0; i < checkedListBoxSectors.Items.Count; i++) + checkedListBoxSectors.SetItemChecked(i, ctrl.checkedListBoxSectors.GetItemChecked(i)); + } + + public void Update(ThreeDFloor threeDFloor) + { + isnew = false; + + this.threeDFloor = threeDFloor; + + sectorBorderTexture.TextureName = threeDFloor.BorderTexture; + sectorTopFlat.TextureName = threeDFloor.TopFlat; + sectorBottomFlat.TextureName = threeDFloor.BottomFlat; + sectorCeilingHeight.Text = threeDFloor.TopHeight.ToString(); + sectorFloorHeight.Text = threeDFloor.BottomHeight.ToString(); + borderHeightLabel.Text = (threeDFloor.TopHeight - threeDFloor.BottomHeight).ToString(); + + typeArgument.Setup(General.Map.Config.LinedefActions[160].Args[1]); + flagsArgument.Setup(General.Map.Config.LinedefActions[160].Args[2]); + alphaArgument.Setup(General.Map.Config.LinedefActions[160].Args[3]); + + typeArgument.SetValue(threeDFloor.Type); + flagsArgument.SetValue(threeDFloor.Flags); + alphaArgument.SetValue(threeDFloor.Alpha); + sectorBrightness.Text = threeDFloor.Brightness.ToString(); + + AddSectorCheckboxes(); + + if(sector == null || sector.IsDisposed) + sector = General.Map.Map.CreateSector(); + + if (threeDFloor.Sector != null) + { + threeDFloor.Sector.CopyPropertiesTo(sector); + tagsLabel.Text = String.Join(", ", sector.Tags.Select(o => o.ToString()).ToArray()); + } + + if (sector != null && !sector.IsDisposed) + sector.Selected = false; + } + + public void ApplyToThreeDFloor() + { + Regex r = new Regex(@"\d+"); + + threeDFloor.TopHeight = sectorCeilingHeight.GetResult(threeDFloor.TopHeight); + threeDFloor.BottomHeight = sectorFloorHeight.GetResult(threeDFloor.BottomHeight); + threeDFloor.TopFlat = sectorTopFlat.TextureName; + threeDFloor.BottomFlat = sectorBottomFlat.TextureName; + threeDFloor.BorderTexture = sectorBorderTexture.TextureName; + + threeDFloor.Type = int.Parse(typeArgument.Text); + threeDFloor.Flags = int.Parse(flagsArgument.Text); + threeDFloor.Alpha = int.Parse(alphaArgument.Text); + threeDFloor.Brightness = sectorBrightness.GetResult(threeDFloor.Brightness); + + threeDFloor.Tags = sector.Tags; + + threeDFloor.IsNew = isnew; + + if (threeDFloor.Sector != null) + { + sector.CopyPropertiesTo(threeDFloor.Sector); + tagsLabel.Text = String.Join(", ", sector.Tags.Select(o => o.ToString()).ToArray()); + } + + threeDFloor.TaggedSectors = new List(); + + for (int i = 0; i < checkedListBoxSectors.Items.Count; i++) + { + string text = checkedListBoxSectors.Items[i].ToString(); + bool ischecked = !(checkedListBoxSectors.GetItemCheckState(i) == CheckState.Unchecked); + + if (ischecked) + { + var matches = r.Matches(text); + Sector s = General.Map.Map.GetSectorByIndex(int.Parse(matches[0].ToString())); + threeDFloor.TaggedSectors.Add(s); + } + } + } + + private void AddSectorCheckboxes() + { + List sectors = new List(BuilderPlug.TDFEW.SelectedSectors.OrderBy(o => o.Index)); + + checkedsectors = new List(); + + checkedListBoxSectors.Items.Clear(); + + foreach (Sector s in ThreeDFloor.TaggedSectors) + { + if (!sectors.Contains(s)) + sectors.Add(s); + } + + if (sectors == null) + return; + + foreach (Sector s in sectors) + { + int i = checkedListBoxSectors.Items.Add("Sector " + s.Index.ToString(), ThreeDFloor.TaggedSectors.Contains(s)); + + if(ThreeDFloor.TaggedSectors.Contains(s)) + checkedsectors.Add(s.Index); + + if (!BuilderPlug.TDFEW.SelectedSectors.Contains(s)) + { + checkedListBoxSectors.SetItemCheckState(i, CheckState.Indeterminate); + } + } + } + + private void buttonDuplicate_Click(object sender, EventArgs e) + { + ((ThreeDFloorEditorWindow)this.ParentForm).DuplicateThreeDFloor(this); + } + + private void buttonSplit_Click(object sender, EventArgs e) + { + ((ThreeDFloorEditorWindow)this.ParentForm).SplitThreeDFloor(this); + } + + private void buttonCheckAll_Click(object sender, EventArgs e) + { + for (int i = 0; i < checkedListBoxSectors.Items.Count; i++) + checkedListBoxSectors.SetItemChecked(i, true); + } + + private void buttonUncheckAll_Click(object sender, EventArgs e) + { + for (int i = 0; i < checkedListBoxSectors.Items.Count; i++) + checkedListBoxSectors.SetItemChecked(i, false); + } + + private void buttonEditSector_Click(object sender, EventArgs e) + { + sector.SetCeilTexture(sectorTopFlat.TextureName); + sector.SetFloorTexture(sectorBottomFlat.TextureName); + sector.CeilHeight = sectorCeilingHeight.GetResult(sector.CeilHeight); + sector.FloorHeight = sectorFloorHeight.GetResult(sector.FloorHeight); + sector.Brightness = sectorBrightness.GetResult(sector.Brightness); + + DialogResult result = General.Interface.ShowEditSectors(new List { sector }); + + if (result == DialogResult.OK) + { + sectorTopFlat.TextureName = sector.CeilTexture; + sectorBottomFlat.TextureName = sector.FloorTexture; + sectorCeilingHeight.Text = sector.CeilHeight.ToString(); + sectorFloorHeight.Text = sector.FloorHeight.ToString(); + sectorBrightness.Text = sector.Brightness.ToString(); + tagsLabel.Text = String.Join(", ", sector.Tags.Select(o => o.ToString()).ToArray()); + } + } + + private void checkedListBoxSectors_ItemCheck(object sender, ItemCheckEventArgs e) + { + if (e.CurrentValue == CheckState.Indeterminate) + { + e.NewValue = CheckState.Indeterminate; + } + else + { + Regex r = new Regex(@"\d+"); + + if (((ListBox)sender).SelectedItem == null) + return; + + var matches = r.Matches(((ListBox)sender).SelectedItem.ToString()); + + int sectornum = int.Parse(matches[0].ToString()); + + if (e.NewValue == CheckState.Checked) + checkedsectors.Add(sectornum); + else + checkedsectors.Remove(sectornum); + } + } + + private void ThreeDFloorHelperControl_Paint(object sender, PaintEventArgs e) + { + Color c = Color.FromArgb(0, 192, 0); // Color.FromArgb(255, Color.Green); + + if (isnew) + ControlPaint.DrawBorder( + e.Graphics, + this.ClientRectangle, + c, // leftColor + 5, // leftWidth + ButtonBorderStyle.Solid, // leftStyle + c, // topColor + 0, // topWidth + ButtonBorderStyle.None, // topStyle + c, // rightColor + 0, // rightWidth + ButtonBorderStyle.None, // rightStyle + c, // bottomColor + 0, // bottomWidth + ButtonBorderStyle.None // bottomStyle + ); + } + + private void RecomputeBorderHeight(object sender, EventArgs e) + { + borderHeightLabel.Text = (sectorCeilingHeight.GetResult(threeDFloor.TopHeight) - sectorFloorHeight.GetResult(threeDFloor.BottomHeight)).ToString(); + } + + private void buttonDetach_Click(object sender, EventArgs e) + { + ((ThreeDFloorEditorWindow)this.ParentForm).DetachThreeDFloor(this); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.resx b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.resx new file mode 100644 index 00000000..d58980a3 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.Designer.cs b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.Designer.cs new file mode 100644 index 00000000..d100853d --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.Designer.cs @@ -0,0 +1,165 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ThreeDFloorHelperTooltipElementControl + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Komponenten-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.sectorTopFlat = new System.Windows.Forms.Panel(); + this.sectorBorderTexture = new System.Windows.Forms.Panel(); + this.sectorBottomFlat = new System.Windows.Forms.Panel(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.bottomHeight = new System.Windows.Forms.Label(); + this.topHeight = new System.Windows.Forms.Label(); + this.borderHeight = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // sectorTopFlat + // + this.sectorTopFlat.BackColor = System.Drawing.SystemColors.AppWorkspace; + this.sectorTopFlat.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.sectorTopFlat.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.sectorTopFlat.Location = new System.Drawing.Point(12, 16); + this.sectorTopFlat.Name = "sectorTopFlat"; + this.sectorTopFlat.Size = new System.Drawing.Size(65, 65); + this.sectorTopFlat.TabIndex = 22; + // + // sectorBorderTexture + // + this.sectorBorderTexture.BackColor = System.Drawing.SystemColors.AppWorkspace; + this.sectorBorderTexture.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.sectorBorderTexture.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.sectorBorderTexture.Location = new System.Drawing.Point(83, 16); + this.sectorBorderTexture.Name = "sectorBorderTexture"; + this.sectorBorderTexture.Size = new System.Drawing.Size(65, 65); + this.sectorBorderTexture.TabIndex = 21; + // + // sectorBottomFlat + // + this.sectorBottomFlat.BackColor = System.Drawing.SystemColors.AppWorkspace; + this.sectorBottomFlat.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.sectorBottomFlat.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.sectorBottomFlat.Location = new System.Drawing.Point(154, 16); + this.sectorBottomFlat.Name = "sectorBottomFlat"; + this.sectorBottomFlat.Size = new System.Drawing.Size(65, 65); + this.sectorBottomFlat.TabIndex = 20; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.BackColor = System.Drawing.Color.Transparent; + this.label3.Location = new System.Drawing.Point(80, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(38, 13); + this.label3.TabIndex = 19; + this.label3.Text = "Border"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.BackColor = System.Drawing.Color.Transparent; + this.label2.Location = new System.Drawing.Point(151, 0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(40, 13); + this.label2.TabIndex = 18; + this.label2.Text = "Bottom"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.BackColor = System.Drawing.Color.Transparent; + this.label1.Location = new System.Drawing.Point(9, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(26, 13); + this.label1.TabIndex = 17; + this.label1.Text = "Top"; + // + // bottomHeight + // + this.bottomHeight.BackColor = System.Drawing.Color.Transparent; + this.bottomHeight.Location = new System.Drawing.Point(189, 0); + this.bottomHeight.Name = "bottomHeight"; + this.bottomHeight.Size = new System.Drawing.Size(30, 13); + this.bottomHeight.TabIndex = 23; + this.bottomHeight.Text = "X"; + this.bottomHeight.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // topHeight + // + this.topHeight.BackColor = System.Drawing.Color.Transparent; + this.topHeight.Location = new System.Drawing.Point(47, 0); + this.topHeight.Name = "topHeight"; + this.topHeight.Size = new System.Drawing.Size(30, 13); + this.topHeight.TabIndex = 24; + this.topHeight.Text = "X"; + this.topHeight.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // borderHeight + // + this.borderHeight.BackColor = System.Drawing.Color.Transparent; + this.borderHeight.Location = new System.Drawing.Point(114, 0); + this.borderHeight.Name = "borderHeight"; + this.borderHeight.Size = new System.Drawing.Size(30, 13); + this.borderHeight.TabIndex = 25; + this.borderHeight.Text = "X"; + this.borderHeight.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // ThreeDFloorHelperTooltipElementControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.borderHeight); + this.Controls.Add(this.topHeight); + this.Controls.Add(this.bottomHeight); + this.Controls.Add(this.sectorTopFlat); + this.Controls.Add(this.sectorBorderTexture); + this.Controls.Add(this.sectorBottomFlat); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Name = "ThreeDFloorHelperTooltipElementControl"; + this.Size = new System.Drawing.Size(222, 82); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.ThreeDFloorHelperTooltipElementControl_Paint); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + public System.Windows.Forms.Panel sectorBorderTexture; + public System.Windows.Forms.Panel sectorTopFlat; + public System.Windows.Forms.Panel sectorBottomFlat; + public System.Windows.Forms.Label bottomHeight; + public System.Windows.Forms.Label topHeight; + public System.Windows.Forms.Label borderHeight; + } +} diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.cs b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.cs new file mode 100644 index 00000000..99fb7fe8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ThreeDFloorHelperTooltipElementControl : UserControl + { + private bool highlighted; + + public bool Highlighted { get { return highlighted; } set { highlighted = value; } } + + public ThreeDFloorHelperTooltipElementControl() + { + highlighted = false; + + InitializeComponent(); + } + + private void ThreeDFloorHelperTooltipElementControl_Paint(object sender, PaintEventArgs e) + { + Color c = Color.FromArgb(0, 192, 0); // Color.FromArgb(255, Color.Green); + + ControlPaint.DrawBorder( + e.Graphics, + this.ClientRectangle, + c, // leftColor + 5, // leftWidth + highlighted ? ButtonBorderStyle.Solid : ButtonBorderStyle.None, // leftStyle + c, // topColor + 0, // topWidth + ButtonBorderStyle.None, // topStyle + c, // rightColor + 0, // rightWidth + ButtonBorderStyle.None, // rightStyle + c, // bottomColor + 0, // bottomWidth + ButtonBorderStyle.None // bottomStyle + ); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.resx b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.resx new file mode 100644 index 00000000..d58980a3 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/DrawSlopesMode.cs b/Source/Plugins/3DFloorMode/DrawSlopesMode.cs new file mode 100644 index 00000000..2539aa12 --- /dev/null +++ b/Source/Plugins/3DFloorMode/DrawSlopesMode.cs @@ -0,0 +1,892 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Linq; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Geometry; +using System.Drawing; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Actions; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + enum SlopeDrawingMode { Floor, Ceiling, FloorAndCeiling }; + + [EditMode(DisplayName = "Draw Slopes Mode", + SwitchAction = "drawslopesmode", + ButtonImage = "DrawSlopeModeIcon.png", // Image resource name for the button + ButtonOrder = int.MinValue + 501, // Position of the button (lower is more to the left) + ButtonGroup = "000_editing", + AllowCopyPaste = false, + SupportedMapFormats = new[] { "UniversalMapSetIO" }, + Volatile = true, + UseByDefault = true, + Optional = false)] + + public class DrawSlopesMode : ClassicMode + { + #region ================== Constants + + private const float LINE_THICKNESS = 0.8f; + + #endregion + + #region ================== Variables + + // Drawing points + private List points; + + // Keep track of view changes + private float lastoffsetx; + private float lastoffsety; + private float lastscale; + + // Options + private bool snaptogrid; // SHIFT to toggle + private bool snaptonearest; // CTRL to enable + + private FlatVertex[] overlayGeometry; + private List labels; + + private static SlopeDrawingMode slopedrawingmode = SlopeDrawingMode.Floor; + + #endregion + + #region ================== Properties + + // Just keep the base mode button checked + public override string EditModeButtonName { get { return General.Editing.PreviousStableMode.Name; } } + + #endregion + + #region ================== Constructor / Disposer + + // Constructor + public DrawSlopesMode() + { + // Initialize + points = new List(); + + // No selection in this mode + //General.Map.Map.ClearAllSelected(); + //General.Map.Map.ClearAllMarks(false); + + // We have no destructor + GC.SuppressFinalize(this); + } + + // Disposer + public override void Dispose() + { + // Not already disposed? + if (!isdisposed) + { + // Dispose old labels + if (labels != null) + foreach (TextLabel l in labels) + l.Dispose(); + + // Done + base.Dispose(); + } + } + + #endregion + + #region ================== Methods + + // This checks if the view offset/zoom changed and updates the check + protected bool CheckViewChanged() + { + bool viewchanged = false; + + // View changed? + if (renderer.OffsetX != lastoffsetx) viewchanged = true; + if (renderer.OffsetY != lastoffsety) viewchanged = true; + if (renderer.Scale != lastscale) viewchanged = true; + + // Keep view information + lastoffsetx = renderer.OffsetX; + lastoffsety = renderer.OffsetY; + lastscale = renderer.Scale; + + // Return result + return viewchanged; + } + + // This sets up new labels + /* + private void SetupLabels() + { + if (labels != null) + { + // Dispose old labels + foreach (KeyValuePair lbl in labels) + foreach (TextLabel l in lbl.Value) l.Dispose(); + } + + // Make text labels for sectors + labels = new Dictionary(General.Map.Map.Sectors.Count); + foreach (Sector s in General.Map.Map.Sectors) + { + // Setup labels + TextLabel[] labelarray = new TextLabel[s.Labels.Count]; + for (int i = 0; i < s.Labels.Count; i++) + { + Vector2D v = s.Labels[i].position; + labelarray[i] = new TextLabel(20); + labelarray[i].TransformCoords = true; + labelarray[i].Rectangle = new RectangleF(v.x, v.y, 0.0f, 0.0f); + labelarray[i].AlignX = TextAlignmentX.Center; + labelarray[i].AlignY = TextAlignmentY.Middle; + labelarray[i].Scale = 14f; + labelarray[i].Color = General.Colors.Highlight.WithAlpha(255); + labelarray[i].Backcolor = General.Colors.Background.WithAlpha(255); + } + labels.Add(s, labelarray); + } + } + */ + + private void SetupLabels() + { + labels = new List(); + PixelColor white = new PixelColor(255, 255, 255, 255); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + for (int i = 0; i < svg.Vertices.Count; i++) + { + if (BuilderPlug.Me.SlopeVertexLabelDisplayOption == LabelDisplayOption.Always || General.Interface.AltState == true) + { + SlopeVertex sv = svg.Vertices[i]; + float scale = 1 / renderer.Scale; + float x = sv.Pos.x; + float y = sv.Pos.y - 14 * scale; + string value = String.Format("Z: {0}", sv.Z); + bool showlabel = true; + + // Rearrange labels if they'd be (exactly) on each other + foreach (TextLabel l in labels) + { + if (l.Location.x == x && l.Location.y == y) { + // Reduce visual clutter by de-duping stacked labels, when "show all labels" is enabled + if (l.Text == value) { + showlabel = false; //dedupe + } else { + // Adjust the label position down one line + y -= l.TextSize.Height * scale; + } + } + } + + // Only proceed if the label was not deduped + if (showlabel) + { + TextLabel label = new TextLabel(); + label.TransformCoords = true; + label.Location = new Vector2D(x, y); + label.AlignX = TextAlignmentX.Center; + label.AlignY = TextAlignmentY.Middle; + label.BackColor = General.Colors.Background.WithAlpha(128); + label.Text = value; + label.Color = white; + + labels.Add(label); + } + } + } + } + } + + // This updates the dragging + private void Update() + { + PixelColor stitchcolor = General.Colors.Highlight; + PixelColor losecolor = General.Colors.Selection; + PixelColor color; + + snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; + snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge; + + DrawnVertex lastp = new DrawnVertex(); + DrawnVertex curp = GetCurrentPosition(); + float vsize = ((float)renderer.VertexSize + 1.0f) / renderer.Scale; + float vsizeborder = ((float)renderer.VertexSize + 3.0f) / renderer.Scale; + + SetupLabels(); + + // Render drawing lines + if (renderer.StartOverlay(true)) + { + float size = 9 / renderer.Scale; + + if (BuilderPlug.Me.UseHighlight) + { + renderer.RenderHighlight(overlayGeometry, General.Colors.Selection.WithAlpha(64).ToInt()); + } + + List vertices = new List(); + + // Store all slope vertices and draw the lines between them + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + for (int i = 0; i < svg.Vertices.Count; i++) + { + vertices.Add(svg.Vertices[i]); + + if (i < svg.Vertices.Count - 1) + renderer.RenderLine(svg.Vertices[0].Pos, svg.Vertices[i + 1].Pos, 1, new PixelColor(255, 255, 255, 255), true); + } + } + + // Sort the slope vertex list and draw them. The sorting ensures that selected vertices are always drawn on top + foreach (SlopeVertex sv in vertices.OrderBy(o => o.Selected)) + { + PixelColor c = General.Colors.Indication; + Vector3D v = sv.Pos; + + renderer.RenderRectangleFilled(new RectangleF(v.x - size / 2, v.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(v.x - size / 2, v.y - size / 2, size, size), 2, c, true); + } + + + // Go for all points to draw lines + if (points.Count > 0) + { + // Render lines + lastp = points[0]; + for (int i = 1; i < points.Count; i++) + { + // Determine line color + if (lastp.stitchline && points[i].stitchline) color = stitchcolor; + else color = losecolor; + + // Render line + renderer.RenderLine(points[0].pos, points[i].pos, LINE_THICKNESS, color, true); + lastp = points[i]; + } + + // Determine line color + if (lastp.stitchline && snaptonearest) color = stitchcolor; + else color = losecolor; + + // Render line to cursor + renderer.RenderLine(points[0].pos, curp.pos, LINE_THICKNESS, color, true); + + // Render vertices + for (int i = 0; i < points.Count; i++) + { + // Determine vertex color + if (points[i].stitch) color = stitchcolor; + else color = losecolor; + + // Render vertex + //renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true); + renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - size / 2, points[i].pos.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(points[i].pos.x - size / 2, points[i].pos.y - size / 2, size, size), 2, General.Colors.Indication, true); + } + } + + foreach (TextLabel l in labels) + renderer.RenderText(l); + + // Determine point color + if (snaptonearest) color = stitchcolor; + else color = losecolor; + + // Render vertex at cursor + //renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - vsize, curp.pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true); + + renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - size / 2, curp.pos.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(curp.pos.x - size / 2, curp.pos.y - size / 2, size, size), 2, General.Colors.Indication, true); + + // Done + renderer.Finish(); + } + + // Done + renderer.Present(); + } + + private void updateOverlaySurfaces() + { + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + List vertsList = new List(); + + // Go for all selected sectors + foreach (Sector s in orderedselection) vertsList.AddRange(s.FlatVertices); + overlayGeometry = vertsList.ToArray(); + } + + // This returns the aligned and snapped draw position + public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, IRenderer2D renderer, List points) + { + DrawnVertex p = new DrawnVertex(); + Vector2D vm = mousemappos; + float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; + + // Snap to nearest? + if (snaptonearest) + { + // Go for all drawn points + foreach (DrawnVertex v in points) + { + if (Vector2D.DistanceSq(mousemappos, v.pos) < (vrange * vrange)) + { + p.pos = v.pos; + p.stitch = true; + p.stitchline = true; + return p; + } + } + + // Try the nearest vertex + Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange); + if (nv != null) + { + p.pos = nv.Position; + p.stitch = true; + p.stitchline = true; + return p; + } + + // Try the nearest linedef + Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.StitchRange / renderer.Scale); + if (nl != null) + { + // Snap to grid? + if (snaptogrid) + { + // Get grid intersection coordinates + List coords = nl.GetGridIntersections(); + + // Find nearest grid intersection + bool found = false; + float found_distance = float.MaxValue; + Vector2D found_coord = new Vector2D(); + foreach (Vector2D v in coords) + { + Vector2D delta = mousemappos - v; + if (delta.GetLengthSq() < found_distance) + { + found_distance = delta.GetLengthSq(); + found_coord = v; + found = true; + } + } + + if (found) + { + // Align to the closest grid intersection + p.pos = found_coord; + p.stitch = true; + p.stitchline = true; + return p; + } + } + else + { + // Aligned to line + p.pos = nl.NearestOnLine(mousemappos); + p.stitch = true; + p.stitchline = true; + return p; + } + } + } + else + { + // Always snap to the first drawn vertex so that the user can finish a complete sector without stitching + if (points.Count > 0) + { + if (Vector2D.DistanceSq(mousemappos, points[0].pos) < (vrange * vrange)) + { + p.pos = points[0].pos; + p.stitch = true; + p.stitchline = false; + return p; + } + } + } + + // if the mouse cursor is outside the map bondaries check if the line between the last set point and the + // mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection + if (points.Count > 0 && + (mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary || + mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary)) + { + Line2D dline = new Line2D(mousemappos, points[points.Count - 1].pos); + bool foundintersection = false; + float u = 0.0f; + List blines = new List(); + + // lines for left, top, right and bottom bondaries + blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary)); + blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary)); + blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary)); + blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary)); + + // check for intersections with boundaries + for (int i = 0; i < blines.Count; i++) + { + if (!foundintersection) + { + // only check for intersection if the last set point is not on the + // line we are checking against + if (blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f) + { + foundintersection = blines[i].GetIntersection(dline, out u); + } + } + } + + // if there was no intersection set the position to the last set point + if (!foundintersection) + vm = points[points.Count - 1].pos; + else + vm = dline.GetCoordinatesAt(u); + + } + + + // Snap to grid? + if (snaptogrid) + { + // Aligned to grid + p.pos = General.Map.Grid.SnappedToGrid(vm); + + // special handling + if (p.pos.x > General.Map.Config.RightBoundary) p.pos.x = General.Map.Config.RightBoundary; + if (p.pos.y < General.Map.Config.BottomBoundary) p.pos.y = General.Map.Config.BottomBoundary; + p.stitch = snaptonearest; + p.stitchline = snaptonearest; + return p; + } + else + { + // Normal position + p.pos = vm; + p.stitch = snaptonearest; + p.stitchline = snaptonearest; + return p; + } + } + + // This gets the aligned and snapped draw position + private DrawnVertex GetCurrentPosition() + { + return GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, renderer, points); + } + + // This draws a point at a specific location + public bool DrawPointAt(DrawnVertex p) + { + return DrawPointAt(p.pos, p.stitch, p.stitchline); + } + + // This draws a point at a specific location + public bool DrawPointAt(Vector2D pos, bool stitch, bool stitchline) + { + if (pos.x < General.Map.Config.LeftBoundary || pos.x > General.Map.Config.RightBoundary || + pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary) + return false; + + DrawnVertex newpoint = new DrawnVertex(); + newpoint.pos = pos; + newpoint.stitch = stitch; + newpoint.stitchline = stitchline; + points.Add(newpoint); + updateOverlaySurfaces(); + Update(); + + if (points.Count == 3) + FinishDraw(); + + return true; + } + + private bool IsControlSector(Sector s) + { + //Determine whether or not the sector is actually a control sector for a 3D floor + foreach (Sidedef sd in s.Sidedefs) + { + if (sd.Line.Action == 160) + return true; + } + return false; + } + + #endregion + + #region ================== Events + + public override void OnHelp() + { + General.ShowHelp("e_drawgeometry.html"); + } + + // Engaging + public override void OnEngage() + { + base.OnEngage(); + + if (BuilderPlug.Me.SlopeDataSector == null || BuilderPlug.Me.SlopeDataSector.IsDisposed) + { + General.Map.UndoRedo.CreateUndo("Set up slope data sector"); + + SlopeDataSectorDialog sdsd = new SlopeDataSectorDialog(); + DialogResult dr = sdsd.ShowDialog(); + + if (dr == DialogResult.Cancel) + { + General.Map.UndoRedo.WithdrawUndo(); + General.Editing.CancelMode(); + return; + } + + if (dr == DialogResult.OK) + { + BuilderPlug.Me.SlopeDataSector = General.Map.Map.GetMarkedSectors(true)[0]; + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + } + } + else + { + BuilderPlug.Me.LoadSlopeVertexGroupsFromSector(); + } + + EnableAutoPanning(); + renderer.SetPresentation(Presentation.Standard); + + // Convert geometry selection to sectors only + General.Map.Map.ConvertSelection(SelectionType.Sectors); + + General.Interface.AddButton(BuilderPlug.Me.MenusForm.FloorSlope); + General.Interface.AddButton(BuilderPlug.Me.MenusForm.CeilingSlope); + General.Interface.AddButton(BuilderPlug.Me.MenusForm.FloorAndCeilingSlope); + + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + if (slopedrawingmode == SlopeDrawingMode.Floor) + BuilderPlug.Me.MenusForm.FloorSlope.Checked = true; + else if (slopedrawingmode == SlopeDrawingMode.Ceiling) + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = true; + else + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = true; + + // Make text labels for sectors + SetupLabels(); + updateOverlaySurfaces(); + Update(); + + // Set cursor + General.Interface.SetCursor(Cursors.Cross); + } + + // Disengaging + public override void OnDisengage() + { + base.OnDisengage(); + + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.FloorSlope); + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.CeilingSlope); + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.FloorAndCeilingSlope); + + DisableAutoPanning(); + } + + // Cancelled + public override void OnCancel() + { + // Cancel base class + base.OnCancel(); + + // Return to previous stable mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } + + // Accepted + public override void OnAccept() + { + Cursor.Current = Cursors.AppStarting; + + General.Settings.FindDefaultDrawSettings(); + + // When points have been drawn + if (points.Count > 1) + { + // Make undo for the draw + General.Map.UndoRedo.CreateUndo("Draw slope"); + + List sv_floor = new List(); + List sv_ceiling = new List(); + + // Fills the slope vertex list for both floor and ceiling slopes. Alos tried + // to determine the default z position of the vertex + List selected = (List)General.Map.Map.GetSelectedSectors(true); + if (selected.Count == 1 && IsControlSector(selected[0])) + { + //If a 3D floor control sector is selected, then just use the height of it directly + float zf = selected[0].FloorHeight; + float zc = selected[0].CeilHeight; + for (int i = 0; i < points.Count; i++) + { + sv_floor.Add(new SlopeVertex(points[i].pos, zf)); + sv_ceiling.Add(new SlopeVertex(points[i].pos, zc)); + } + } else { + //For normal sectors, grab the height of the sector each control handle lies within + for (int i = 0; i < points.Count; i++) + { + float zf = 0; + float zc = 0; + Sector s = General.Map.Map.GetSectorByCoordinates(points[i].pos); + + if (s != null) + { + foreach (Sidedef sd in s.Sidedefs) + { + if (sd.Line.Line.GetSideOfLine(points[i].pos) == 0) + { + if (sd.Line.Back != null && !selected.Contains(sd.Line.Back.Sector)) + { + zf = sd.Line.Back.Sector.FloorHeight; + zc = sd.Line.Back.Sector.CeilHeight; + } + else + { + zf = sd.Line.Front.Sector.FloorHeight; + zc = sd.Line.Front.Sector.CeilHeight; + } + } + } + } + + sv_floor.Add(new SlopeVertex(points[i].pos, zf)); + sv_ceiling.Add(new SlopeVertex(points[i].pos, zc)); + } + } + + // Create the floor slope vertex group and add it to all selected sectors + if (slopedrawingmode == SlopeDrawingMode.Floor || slopedrawingmode == SlopeDrawingMode.FloorAndCeiling) + { + int id = -1; + SlopeVertexGroup svg = BuilderPlug.Me.AddSlopeVertexGroup(sv_floor, out id); + + svg.Sectors.Clear(); + + foreach (Sector s in selected) + { + // Make sure the field work with undo/redo + s.Fields.BeforeFieldsChange(); + + if (s.Fields.ContainsKey("user_floorplane_id")) + s.Fields.Remove("user_floorplane_id"); + + s.Fields.Add("user_floorplane_id", new UniValue(UniversalType.Integer, id)); + + // svg.Sectors.Add(s); + + svg.AddSector(s, PlaneType.Floor); + } + } + + // Create the ceiling slope vertex group and add it to all selected sectors + if (slopedrawingmode == SlopeDrawingMode.Ceiling || slopedrawingmode == SlopeDrawingMode.FloorAndCeiling) + { + int id = -1; + SlopeVertexGroup svg = BuilderPlug.Me.AddSlopeVertexGroup(sv_ceiling, out id); + + svg.Sectors.Clear(); + + foreach (Sector s in selected) + { + // Make sure the field work with undo/redo + s.Fields.BeforeFieldsChange(); + + if (s.Fields.ContainsKey("user_ceilingplane_id")) + s.Fields.Remove("user_ceilingplane_id"); + + s.Fields.Add("user_ceilingplane_id", new UniValue(UniversalType.Integer, id)); + + // svg.Sectors.Add(s); + svg.AddSector(s, PlaneType.Ceiling); + } + } + + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + + // BuilderPlug.Me.UpdateSlopes(); + + // Clear selection + General.Map.Map.ClearAllSelected(); + + // Update cached values + General.Map.Map.Update(); + + // Map is changed + General.Map.IsChanged = true; + } + + // Done + Cursor.Current = Cursors.Default; + + // Return to original mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } + + // This redraws the display + public override void OnRedrawDisplay() + { + renderer.RedrawSurface(); + + // Render lines + if (renderer.StartPlotter(true)) + { + renderer.PlotLinedefSet(General.Map.Map.Linedefs); + renderer.PlotVerticesSet(General.Map.Map.Vertices); + renderer.Finish(); + } + + // Render things + if (renderer.StartThings(true)) + { + renderer.RenderThingSet(General.Map.Map.Things, 1.0f); + renderer.Finish(); + } + + // Normal update + updateOverlaySurfaces(); + Update(); + } + + // Mouse moving + public override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + updateOverlaySurfaces(); + Update(); + } + + // When a key is released + public override void OnKeyUp(KeyEventArgs e) + { + base.OnKeyUp(e); + if ((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) || + (snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update(); + } + + // When a key is pressed + public override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if ((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) || + (snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update(); + } + + #endregion + + #region ================== Actions + + [BeginAction("drawfloorslope")] + public void DrawFloorSlope() + { + slopedrawingmode = SlopeDrawingMode.Floor; + + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = true; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to floor"); + } + + [BeginAction("drawceilingslope")] + public void DrawCeilingSlope() + { + slopedrawingmode = SlopeDrawingMode.Ceiling; + + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = true; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to ceiling"); + } + + [BeginAction("drawfloorandceilingslope")] + public void DrawFloorAndCeilingSlope() + { + slopedrawingmode = SlopeDrawingMode.FloorAndCeiling; + + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = true; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to floor and ceiling"); + } + + // Drawing a point + [BeginAction("drawslopepoint")] + public void DrawPoint() + { + // Mouse inside window? + if (General.Interface.MouseInDisplay) + { + DrawnVertex newpoint = GetCurrentPosition(); + + if (!DrawPointAt(newpoint)) General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries."); + } + } + + // Remove a point + //[BeginAction("removepoint")] + public void RemovePoint() + { + if (points.Count > 0) points.RemoveAt(points.Count - 1); + + updateOverlaySurfaces(); + Update(); + } + + // Finish drawing + [BeginAction("finishslopedraw")] + public void FinishDraw() + { + // Accept the changes + General.Editing.AcceptMode(); + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/Interface/PreferencesForm.Designer.cs b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.Designer.cs new file mode 100644 index 00000000..d425c21c --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.Designer.cs @@ -0,0 +1,163 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class PreferencesForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tabs = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.sectorlabels = new System.Windows.Forms.ComboBox(); + this.slopevertexlabels = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tabs.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // tabs + // + this.tabs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabs.Controls.Add(this.tabPage1); + this.tabs.Location = new System.Drawing.Point(12, 12); + this.tabs.Name = "tabs"; + this.tabs.SelectedIndex = 0; + this.tabs.Size = new System.Drawing.Size(677, 454); + this.tabs.TabIndex = 0; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.groupBox1); + this.tabPage1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(669, 428); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "3D Floor Plugin"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.slopevertexlabels); + this.groupBox1.Controls.Add(this.sectorlabels); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(6, 6); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(305, 94); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Slope Mode"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(34, 22); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(99, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Show sector labels:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 49); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(127, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Show slope vertex labels:"; + // + // sectorlabels + // + this.sectorlabels.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.sectorlabels.FormattingEnabled = true; + this.sectorlabels.Items.AddRange(new object[] { + "Always", + "Never", + "On slope vertex highlight"}); + this.sectorlabels.Location = new System.Drawing.Point(139, 19); + this.sectorlabels.Name = "sectorlabels"; + this.sectorlabels.Size = new System.Drawing.Size(155, 21); + this.sectorlabels.TabIndex = 2; + // + // slopevertexlabels + // + this.slopevertexlabels.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.slopevertexlabels.FormattingEnabled = true; + this.slopevertexlabels.Items.AddRange(new object[] { + "Always", + "Never", + "On slope vertex highlight"}); + this.slopevertexlabels.Location = new System.Drawing.Point(139, 46); + this.slopevertexlabels.Name = "slopevertexlabels"; + this.slopevertexlabels.Size = new System.Drawing.Size(155, 21); + this.slopevertexlabels.TabIndex = 3; + // + // label3 + // + this.label3.Dock = System.Windows.Forms.DockStyle.Bottom; + this.label3.Location = new System.Drawing.Point(3, 68); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(299, 23); + this.label3.TabIndex = 4; + this.label3.Text = "Holding the Alt key will always show the labels"; + this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // PreferencesForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(701, 478); + this.Controls.Add(this.tabs); + this.Name = "PreferencesForm"; + this.Text = "PreferencesForm"; + this.tabs.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tabs; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.ComboBox slopevertexlabels; + private System.Windows.Forms.ComboBox sectorlabels; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label3; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Interface/PreferencesForm.cs b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.cs new file mode 100644 index 00000000..28843c84 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class PreferencesForm : DelayedForm + { + public PreferencesForm() + { + InitializeComponent(); + + sectorlabels.SelectedIndex = (int)BuilderPlug.Me.SectorLabelDisplayOption; + slopevertexlabels.SelectedIndex = (int)BuilderPlug.Me.SlopeVertexLabelDisplayOption; + } + + #region ================== Methods + + // When OK is pressed on the preferences dialog + public void OnAccept(PreferencesController controller) + { + // Write preferred settings + General.Settings.WritePluginSetting("sectorlabeldisplayoption", sectorlabels.SelectedIndex); + General.Settings.WritePluginSetting("slopevertexlabeldisplayoption", slopevertexlabels.SelectedIndex); + } + + // This sets up the form with the preferences controller + public void Setup(PreferencesController controller) + { + // Add tab pages + foreach (TabPage p in tabs.TabPages) + { + controller.AddTab(p); + } + + // Bind events + controller.OnAccept += OnAccept; + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/Interface/PreferencesForm.resx b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.resx new file mode 100644 index 00000000..7080a7d1 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.Designer.cs b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.Designer.cs new file mode 100644 index 00000000..e98d1482 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.Designer.cs @@ -0,0 +1,63 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ThreeDFloorPanel + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Komponenten-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.SuspendLayout(); + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowLayoutPanel1.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.flowLayoutPanel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowLayoutPanel1.Location = new System.Drawing.Point(4, 4); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(242, 593); + this.flowLayoutPanel1.TabIndex = 0; + // + // ThreeDFloorPanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.flowLayoutPanel1); + this.Name = "ThreeDFloorPanel"; + this.Size = new System.Drawing.Size(249, 600); + this.ResumeLayout(false); + + } + + #endregion + + public System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + + } +} diff --git a/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.cs b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.cs new file mode 100644 index 00000000..a2d47692 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ThreeDFloorPanel : UserControl + { + public ThreeDFloorPanel() + { + InitializeComponent(); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.resx b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.resx new file mode 100644 index 00000000..19dc0dd8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/MergePoint.cs b/Source/Plugins/3DFloorMode/MergePoint.cs new file mode 100644 index 00000000..462a097e --- /dev/null +++ b/Source/Plugins/3DFloorMode/MergePoint.cs @@ -0,0 +1,79 @@ +#region ================== Copyright (c) 2014 Boris Iwanski + +/* + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +using System.Collections.Generic; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class MergePoint + { + private Vector2D position; + private int floorheight; + private int ceilingheight; + private string floortexture; + private string ceilingtexture; + private List threedfloors; + + public Vector2D Position { get { return position; } set { position = value; } } + public int FloorHeight { get { return floorheight; } set { floorheight = value; } } + public int CeilingHeight { get { return ceilingheight; } set { ceilingheight = value; } } + public string FloorTexture { get { return floortexture; } set { floortexture = value; } } + public string CeilingTexture { get { return ceilingtexture; } set { ceilingtexture = value; } } + public List ThreeDFloors { get { return threedfloors; } } + + public MergePoint(Vector2D position) + { + this.position = position; + threedfloors = new List(); + } + + public void Update() + { + List sectors = new List(); + + foreach (Sector s in General.Map.Map.Sectors) + { + if (s.Intersect(position)) + sectors.Add(s); + } + + if (sectors.Count == 0) + return; + + floorheight = sectors[0].FloorHeight; + ceilingheight = sectors[0].CeilHeight; + + floortexture = sectors[0].FloorTexture; + ceilingtexture = sectors[0].CeilTexture; + + foreach (Sector s in sectors) + { + if (s.FloorHeight < floorheight) + { + floorheight = s.FloorHeight; + floortexture = s.FloorTexture; + } + + if (s.CeilHeight > ceilingheight) + { + ceilingheight = s.CeilHeight; + ceilingtexture = s.CeilTexture; + } + } + } + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Properties/AssemblyInfo.cs b/Source/Plugins/3DFloorMode/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d0a90d4f --- /dev/null +++ b/Source/Plugins/3DFloorMode/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("ThreeDFloorMode")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ThreeDFloorMode")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("626ea88b-7e0f-4486-acca-32027c4133de")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("0.1.0.0")] diff --git a/Source/Plugins/3DFloorMode/Properties/Resources.Designer.cs b/Source/Plugins/3DFloorMode/Properties/Resources.Designer.cs new file mode 100644 index 00000000..8baf4b91 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Properties/Resources.Designer.cs @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ThreeDFloorMode.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ThreeDFloorMode.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ceiling { + get { + object obj = ResourceManager.GetObject("Ceiling", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Floor { + get { + object obj = ResourceManager.GetObject("Floor", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap FloorAndCeiling { + get { + object obj = ResourceManager.GetObject("FloorAndCeiling", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Source/Plugins/3DFloorMode/Properties/Resources.resx b/Source/Plugins/3DFloorMode/Properties/Resources.resx new file mode 100644 index 00000000..c8365524 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Properties/Resources.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\Ceiling.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Floor.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\FloorAndCeiling.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Resources/Actions.cfg b/Source/Plugins/3DFloorMode/Resources/Actions.cfg new file mode 100644 index 00000000..e5a23f6c --- /dev/null +++ b/Source/Plugins/3DFloorMode/Resources/Actions.cfg @@ -0,0 +1,156 @@ +// +// This file defines which actions there are, what description they have and +// some behaviour options. The Doom Builder core will bind to these actions +// with delegates (function pointers) where you use the BeginAction and +// EndAction attributes. This file must be named Actions.cfg and must be +// included in the plugin project as "Embedded Resource". +// + +// +// Options: +// +// allowkeys: Allows the user to bind standard keys to this action. +// allowmouse: Allows the user to bind mouse buttons to this action. +// allowscroll: Allows the user to bind the scrollwheel to this action. +// disregardshift: This action will trigger regardless if Shift or Control is used. +// repeat: BeginAction will be called for automatic key repetition. +// default: Default key is only used when the action is loaded for the first +// time and the default key is not used by any other action. +// +// allowkeys and allowmouse are true by default, the others are false by default. +// + +categories +{ + threedfloorplugin = "3D Floor Plugin"; +} + +threedfloorhelpermode +{ + title = "3D floor editing mode"; + category = "threedfloorplugin"; + description = "Edits 3D floors"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +threedslopemode +{ + title = "Slope mode"; + category = "threedfloorplugin"; + description = "Edits slope vertex groups"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +drawslopesmode +{ + title = "Draw slope mode"; + category = "threedfloorplugin"; + description = "Draws a slope vertex group"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +drawslopepoint +{ + title = "Draw slope vertex"; + category = "threedfloorplugin"; + description = "Draws a slope vertex at the mousecursor position."; + allowkeys = true; + allowmouse = true; + allowscroll = true; + disregardshift = true; + disregardcontrol = true; +} + +drawfloorslope +{ + title = "Draw Floor Slope"; + category = "threedfloorplugin"; + description = "The drawn slope will be applied to the floor"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +drawceilingslope +{ + title = "Draw Ceiling Slope"; + category = "threedfloorplugin"; + description = "The drawn slope will be applied to the ceiling"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +drawfloorandceilingslope +{ + title = "Draw Floor and Ceiling Slope"; + category = "threedfloorplugin"; + description = "The drawn slope will be applied to the floor and ceiling"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +finishslopedraw +{ + title = "Finish Slope Drawing"; + category = "threedfloorplugin"; + description = "Finishes the slope drawing."; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +threedflipslope +{ + title = "Flip 3D slope"; + category = "threedfloorplugin"; +} + +cyclehighlighted3dfloorup +{ + title = "Cycle highlighted 3D floor up"; + category = "threedfloorplugin"; + description = "Cycles up through the 3D floors of the currently highlighted sector"; + allowkeys = true; + allowmouse = true; + allowscroll = true; + default = 131066; +} + +cyclehighlighted3dfloordown +{ + title = "Cycle highlighted 3D floor down"; + category = "threedfloorplugin"; + description = "Cycles down through the 3D floors of the currently highlighted sector"; + allowkeys = true; + allowmouse = true; + allowscroll = true; + default = 131067; +} + +relocate3dfloorcontrolsectors +{ + title = "Relocate 3D floor control sectors"; + category = "threedfloorplugin"; + description = "Relocates the managed 3D floor control sectors to the current position of the control sector area"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +select3dfloorcontrolsector +{ + title = "Select 3D floor control sector"; + category = "threedfloorplugin"; + description = "Selects the control sector of the currently highlighted 3D floor. Removes all other selections"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Resources/Ceiling.png b/Source/Plugins/3DFloorMode/Resources/Ceiling.png new file mode 100644 index 00000000..274d42c7 Binary files /dev/null and b/Source/Plugins/3DFloorMode/Resources/Ceiling.png differ diff --git a/Source/Plugins/3DFloorMode/Resources/DrawSlopeModeIcon.png b/Source/Plugins/3DFloorMode/Resources/DrawSlopeModeIcon.png new file mode 100644 index 00000000..b49f6c2d Binary files /dev/null and b/Source/Plugins/3DFloorMode/Resources/DrawSlopeModeIcon.png differ diff --git a/Source/Plugins/3DFloorMode/Resources/Floor.png b/Source/Plugins/3DFloorMode/Resources/Floor.png new file mode 100644 index 00000000..b996c1ac Binary files /dev/null and b/Source/Plugins/3DFloorMode/Resources/Floor.png differ diff --git a/Source/Plugins/3DFloorMode/Resources/FloorAndCeiling.png b/Source/Plugins/3DFloorMode/Resources/FloorAndCeiling.png new file mode 100644 index 00000000..693789ab Binary files /dev/null and b/Source/Plugins/3DFloorMode/Resources/FloorAndCeiling.png differ diff --git a/Source/Plugins/3DFloorMode/Resources/SlopeModeIcon.png b/Source/Plugins/3DFloorMode/Resources/SlopeModeIcon.png new file mode 100644 index 00000000..840b044a Binary files /dev/null and b/Source/Plugins/3DFloorMode/Resources/SlopeModeIcon.png differ diff --git a/Source/Plugins/3DFloorMode/Resources/ThreeDFloorIcon.png b/Source/Plugins/3DFloorMode/Resources/ThreeDFloorIcon.png new file mode 100644 index 00000000..ae79ea25 Binary files /dev/null and b/Source/Plugins/3DFloorMode/Resources/ThreeDFloorIcon.png differ diff --git a/Source/Plugins/3DFloorMode/SectorLabelInfo.cs b/Source/Plugins/3DFloorMode/SectorLabelInfo.cs new file mode 100644 index 00000000..a93d44c7 --- /dev/null +++ b/Source/Plugins/3DFloorMode/SectorLabelInfo.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + class SectorLabelInfo + { + public bool Floor { get { return (planetypes & PlaneType.Floor) == PlaneType.Floor; } } + public bool Ceiling { get { return (planetypes & PlaneType.Ceiling) == PlaneType.Ceiling; } } + public bool Bottom { get { return (planetypes & PlaneType.Bottom) == PlaneType.Bottom; } } + public bool Top { get { return (planetypes & PlaneType.Top) == PlaneType.Top; } } + + private PlaneType planetypes; + private Dictionary> slopevertexgroups; + + public SectorLabelInfo() + { + planetypes = 0; + slopevertexgroups = new Dictionary>(); + + foreach (PlaneType pt in Enum.GetValues(typeof(PlaneType))) + slopevertexgroups.Add(pt, new List()); + } + + public void AddSlopeVertexGroup(PlaneType pt, SlopeVertexGroup svg) + { + if (!slopevertexgroups[pt].Contains(svg)) + slopevertexgroups[pt].Add(svg); + + planetypes |= pt; + } + + public TextLabel[] CreateLabels(Sector sector, SlopeVertex slopevertex, float scale) + { + int numlabels = 0; + int loopcounter = 0; + PixelColor white = new PixelColor(255, 255, 255, 255); + + // Count how many actual labels we have to create at each label position + foreach (PlaneType pt in Enum.GetValues(typeof(PlaneType))) + if ((planetypes & pt) == pt) + numlabels++; + + // Split sectors can have multiple label positions, so we have to create + // numlabels labels for each position + TextLabel[] labels = new TextLabel[sector.Labels.Count * numlabels]; + + foreach (PlaneType pt in Enum.GetValues(typeof(PlaneType))) + { + if ((planetypes & pt) != pt) + continue; + + bool highlighted = false; + + foreach (SlopeVertexGroup svg in slopevertexgroups[pt]) + if (svg.Vertices.Contains(slopevertex)) + highlighted = true; + + for (int i = 0; i < sector.Labels.Count; i++) + { + int apos = sector.Labels.Count * loopcounter + i; + Vector2D location = sector.Labels[i].position; + + location.x += ((-6 * (numlabels-1)) + (loopcounter * 12)) * (1/scale); + + labels[apos] = new TextLabel(); + labels[apos].TransformCoords = true; + labels[apos].AlignX = TextAlignmentX.Center; + labels[apos].AlignY = TextAlignmentY.Middle; + labels[apos].BackColor = General.Colors.Background.WithAlpha(128); + labels[apos].Location = location; + + if (highlighted) + labels[apos].Color = General.Colors.Highlight.WithAlpha(255); + else + labels[apos].Color = white; + + if (pt == PlaneType.Floor) + labels[apos].Text = "F"; + else if (pt == PlaneType.Ceiling) + labels[apos].Text = "C"; + else if (pt == PlaneType.Bottom) + labels[apos].Text = "B"; + else if (pt == PlaneType.Top) + labels[apos].Text = "T"; + } + + loopcounter++; + } + + return labels; + } + + } +} diff --git a/Source/Plugins/3DFloorMode/SlopeMode.cs b/Source/Plugins/3DFloorMode/SlopeMode.cs new file mode 100644 index 00000000..babf15c7 --- /dev/null +++ b/Source/Plugins/3DFloorMode/SlopeMode.cs @@ -0,0 +1,1372 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Drawing; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Linq; +using System.Diagnostics; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.BuilderModes; +// using CodeImp.DoomBuilder.GZBuilder.Geometry; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class SlopeObject + { + private ThreeDFloor threedfloor; + private Vector2D position; + private int v; + + public ThreeDFloor ThreeDFloor { get { return threedfloor; } set { threedfloor = value; } } + public Vector2D Position { get { return position; } set { position = value; } } + public int V { get { return v; } set { v = value; } } + } + + [EditMode(DisplayName = "Slope Mode", + SwitchAction = "threedslopemode", // Action name used to switch to this mode + ButtonImage = "SlopeModeIcon.png", // Image resource name for the button + ButtonOrder = int.MinValue + 501, // Position of the button (lower is more to the left) + ButtonGroup = "000_editing", + SupportedMapFormats = new[] { "UniversalMapSetIO" }, + UseByDefault = true, + SafeStartMode = true)] + + public class SlopeMode : ClassicMode + { + #region ================== Constants + + #endregion + + #region ================== Variables + + // Highlighted item + private SlopeVertex highlightedslope; + private Sector highlightedsector; + private Association[] association = new Association[Thing.NUM_ARGS]; + private List copyslopevertexgroups; + + private List threedfloors; + bool dragging = false; + + private List labels; + private FlatVertex[] overlaygeometry; + private FlatVertex[] overlaytaggedgeometry; + private FlatVertex[] selectedsectorgeometry; + + private Vector2D dragstartmappos; + private List oldpositions; + + private bool contextmenuclosing = false; + + #endregion + + #region ================== Properties + + public Sector HighlightedSector { get { return highlightedsector; } } + public bool ContextMenuClosing { get { return contextmenuclosing; } set { contextmenuclosing = value; } } + + #endregion + + #region ================== Constructor / Disposer + + #endregion + + #region ================== Methods + + public override void OnHelp() + { + General.ShowHelp("e_things.html"); + } + + // Cancel mode + public override void OnCancel() + { + base.OnCancel(); + + // Return to previous stable mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } + + // Mode engages + public override void OnEngage() + { + base.OnEngage(); + + if (BuilderPlug.Me.SlopeDataSector == null || BuilderPlug.Me.SlopeDataSector.IsDisposed) + { + General.Map.UndoRedo.CreateUndo("Set up slope data sector"); + + SlopeDataSectorDialog sdsd = new SlopeDataSectorDialog(); + DialogResult dr = sdsd.ShowDialog(); + + if (dr == DialogResult.Cancel) + { + General.Map.UndoRedo.WithdrawUndo(); + General.Editing.CancelMode(); + return; + } + + if (dr == DialogResult.OK) + { + BuilderPlug.Me.SlopeDataSector = General.Map.Map.GetMarkedSectors(true)[0]; + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + } + } + else + { + BuilderPlug.Me.LoadSlopeVertexGroupsFromSector(); + } + + renderer.SetPresentation(Presentation.Things); + + General.Interface.AddButton(BuilderPlug.Me.MenusForm.UpdateSlopes); + + // Convert geometry selection to sectors + General.Map.Map.ConvertSelection(SelectionType.Sectors); + + // Get all 3D floors in the map + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + + SetupLabels(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + svg.FindSectors(); + } + + // Update overlay surfaces, so that selected sectors are drawn correctly + updateOverlaySurfaces(); + } + + // Mode disengages + public override void OnDisengage() + { + base.OnDisengage(); + + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.UpdateSlopes); + + // Hide highlight info + General.Interface.HideInfo(); + } + + // This redraws the display + public override void OnRedrawDisplay() + { + renderer.RedrawSurface(); + + // Render lines and vertices + if(renderer.StartPlotter(true)) + { + renderer.PlotLinedefSet(General.Map.Map.Linedefs); + renderer.PlotVerticesSet(General.Map.Map.Vertices); + + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + renderer.PlotSector(s, General.Colors.Selection); + + if ((highlightedsector != null) && !highlightedsector.IsDisposed) + renderer.PlotSector(highlightedsector, General.Colors.Highlight); + + renderer.Finish(); + } + + // Render things + if(renderer.StartThings(true)) + { + renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, Presentation.THINGS_HIDDEN_ALPHA); + renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, 1.0f); + + renderer.Finish(); + } + + UpdateOverlay(); + + renderer.Present(); + } + + private void SetupLabels() + { + Dictionary sectorlabels = new Dictionary(); + PixelColor white = new PixelColor(255, 255, 255, 255); + + if (labels != null) + { + // Dispose old labels + foreach (TextLabel l in labels) + l.Dispose(); + + labels.Clear(); + } + else + { + labels = new List(); + } + + // Go through all sectors that belong to a SVG and set which SVG their floor and + // ceiling belongs to + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + // Process all directly affected sectors + foreach (Sector s in svg.Sectors) + { + if(!sectorlabels.ContainsKey(s)) + sectorlabels.Add(s, new SectorLabelInfo()); + + if ((svg.SectorPlanes[s] & PlaneType.Floor) == PlaneType.Floor) + sectorlabels[s].AddSlopeVertexGroup(PlaneType.Floor, svg); + + if ((svg.SectorPlanes[s] & PlaneType.Ceiling) == PlaneType.Ceiling) + sectorlabels[s].AddSlopeVertexGroup(PlaneType.Ceiling, svg); + } + + // Process all tagged sectors + foreach(Sector s in svg.TaggedSectors) + { + if (!sectorlabels.ContainsKey(s)) + sectorlabels.Add(s, new SectorLabelInfo()); + + // Bottom and Top are just virtual, the control sector has Floor and Ceiling + if ((svg.SectorPlanes[s] & PlaneType.Floor) == PlaneType.Floor) + sectorlabels[s].AddSlopeVertexGroup(PlaneType.Bottom, svg); + + if ((svg.SectorPlanes[s] & PlaneType.Ceiling) == PlaneType.Ceiling) + sectorlabels[s].AddSlopeVertexGroup(PlaneType.Top, svg); + } + } + + // Create the labels for each sector and add them to the label list + if (BuilderPlug.Me.SectorLabelDisplayOption != LabelDisplayOption.Never || General.Interface.AltState == true) + { + foreach (Sector s in sectorlabels.Keys) + { + bool showlabel = true; + + if (BuilderPlug.Me.SectorLabelDisplayOption == LabelDisplayOption.WhenHighlighted && General.Interface.AltState == false) + { + showlabel = false; + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + if ((svg.Sectors.Contains(s) || svg.TaggedSectors.Contains(s)) && svg.Vertices.Contains(highlightedslope)) + showlabel = true; + } + + if(showlabel) + labels.AddRange(sectorlabels[s].CreateLabels(s, highlightedslope, renderer.Scale)); + } + } + + // Z position labels for slope vertices + if (BuilderPlug.Me.SlopeVertexLabelDisplayOption != LabelDisplayOption.Never || General.Interface.AltState == true) + { + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + for (int i = 0; i < svg.Vertices.Count; i++) + { + if (BuilderPlug.Me.SlopeVertexLabelDisplayOption == LabelDisplayOption.Always || General.Interface.AltState == true || svg.Vertices.Contains(highlightedslope)) + { + SlopeVertex sv = svg.Vertices[i]; + float scale = 1 / renderer.Scale; + float x = sv.Pos.x; + float y = sv.Pos.y - 14 * scale; + string value = String.Format("Z: {0}", sv.Z); + bool showlabel = true; + + // Rearrange labels if they'd be (exactly) on each other + // TODO: do something like that also for overlapping labels + foreach (TextLabel l in labels) + { + if (l.Location.x == x && l.Location.y == y) { + // Reduce visual clutter by de-duping stacked labels, when "show all labels" is enabled + if (l.Text == value) { + showlabel = false; //dedupe + + // If any of the shared label lines are highlighted/selected, then override the color + if (svg.Vertices.Contains(highlightedslope)) + l.Color = General.Colors.Highlight.WithAlpha(255); + else if (sv.Selected) + l.Color = General.Colors.Selection.WithAlpha(255); + } else { + // Adjust the label position down one line + y -= l.TextSize.Height * scale; + } + } + } + + // Only proceed if the label was not deduped + if (showlabel) + { + TextLabel label = new TextLabel(); + label.TransformCoords = true; + label.Location = new Vector2D(x, y); + label.AlignX = TextAlignmentX.Center; + label.AlignY = TextAlignmentY.Middle; + label.BackColor = General.Colors.Background.WithAlpha(128); + label.Text = value; + + if (svg.Vertices.Contains(highlightedslope)) + label.Color = General.Colors.Highlight.WithAlpha(255); + else if (sv.Selected) + label.Color = General.Colors.Selection.WithAlpha(255); + else + label.Color = white; + + labels.Add(label); + } + } + } + } + } + } + + // This updates the overlay + private void UpdateOverlay() + { + float size = 9 / renderer.Scale; + + SetupLabels(); + + if (renderer.StartOverlay(true)) + { + if(overlaygeometry != null) + renderer.RenderHighlight(overlaygeometry, General.Colors.ModelWireframe.WithAlpha(64).ToInt()); + + if (overlaytaggedgeometry != null) + renderer.RenderHighlight(overlaytaggedgeometry, General.Colors.Vertices.WithAlpha(64).ToInt()); + + if (selectedsectorgeometry != null) + renderer.RenderHighlight(selectedsectorgeometry, General.Colors.Selection.WithAlpha(64).ToInt()); + + if (BuilderPlug.Me.UseHighlight && highlightedsector != null) + { + renderer.RenderHighlight(highlightedsector.FlatVertices, General.Colors.Highlight.WithAlpha(64).ToInt()); + } + + List vertices = new List(); + List highlightlines = new List(); + + // TMP + foreach(Line3D l in BuilderPlug.Me.drawlines) + { + renderer.RenderLine( + new Vector2D(l.Start.x, l.Start.z), + new Vector2D(l.End.x, l.End.z), + 1, new PixelColor(255, 255, 255, 255), true + ); + } + + foreach(Vector3D v in BuilderPlug.Me.drawpoints) + { + renderer.RenderLine( + new Vector2D(v.x, v.z+2), + new Vector2D(v.x, v.z-2), + 1, new PixelColor(255, 255, 0, 0), true); + } + + // Store all slope vertices and draw the lines between them. If the lines connect highlighted slope vertices + // draw them later, so they are on top + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + bool highlighted = svg.Vertices.Where(o => o == highlightedslope).Count() > 0; + + for (int i = 0; i < svg.Vertices.Count; i++) + { + vertices.Add(svg.Vertices[i]); + + if (i < svg.Vertices.Count - 1) + { + if (highlighted) + highlightlines.Add(new Line2D(svg.Vertices[0].Pos, svg.Vertices[i + 1].Pos)); + else + renderer.RenderLine(svg.Vertices[0].Pos, svg.Vertices[i + 1].Pos, 1, new PixelColor(255, 255, 255, 255), true); + } + } + } + + // Draw highlighted lines + foreach (Line2D line in highlightlines) + renderer.RenderLine(line.v1, line.v2, 1, General.Colors.Highlight, true); + + // Sort the slope vertex list and draw them. The sorting ensures that selected vertices are always drawn on top + foreach(SlopeVertex sv in vertices.OrderBy(o=>o.Selected)) + { + PixelColor c = General.Colors.Indication; + Vector3D v = sv.Pos; + + if (sv.Selected) + c = General.Colors.Selection; + + renderer.RenderRectangleFilled(new RectangleF(v.x - size / 2, v.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(v.x - size / 2, v.y - size / 2, size, size), 2, c, true); + } + + // Draw highlighted slope vertex + if (highlightedslope != null) + { + renderer.RenderRectangleFilled(new RectangleF(highlightedslope.Pos.x - size / 2, highlightedslope.Pos.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(highlightedslope.Pos.x - size / 2, highlightedslope.Pos.y - size / 2, size, size), 2, General.Colors.Highlight, true); + } + + foreach (TextLabel l in labels) + renderer.RenderText(l); + + if (selecting) + RenderMultiSelection(); + + renderer.Finish(); + } + } + + private void updateOverlaySurfaces() + { + string[] fieldnames = new string[] { "user_floorplane_id", "user_ceilingplane_id" }; + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + List vertslist = new List(); + List highlightedsectors = new List(); + List highlightedtaggedsectors = new List(); + + // Highlighted slope + if (highlightedslope != null) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(highlightedslope); + + // All sectors the slope applies to + foreach (Sector s in svg.Sectors) + { + if (s != null && !s.IsDisposed) + { + vertslist.AddRange(s.FlatVertices); + highlightedsectors.Add(s); + } + } + + overlaygeometry = vertslist.ToArray(); + + // All sectors that are tagged because of 3D floors + vertslist = new List(); + + foreach (Sector s in svg.TaggedSectors) + { + if (s != null && !s.IsDisposed) + { + vertslist.AddRange(s.FlatVertices); + highlightedtaggedsectors.Add(s); + } + } + + overlaytaggedgeometry = vertslist.ToArray(); + } + else + { + overlaygeometry = new FlatVertex[0]; + overlaytaggedgeometry = new FlatVertex[0]; + } + + // Selected sectors + vertslist = new List(); + + foreach (Sector s in orderedselection) + if(!highlightedsectors.Contains(s)) + vertslist.AddRange(s.FlatVertices); + + selectedsectorgeometry = vertslist.ToArray(); + } + + // This highlights a new item + protected void HighlightSector(Sector s) + { + // Update display + + highlightedsector = s; + /* + if (renderer.StartPlotter(false)) + { + // Undraw previous highlight + if ((highlightedsector != null) && !highlightedsector.IsDisposed) + renderer.PlotSector(highlightedsector); + + // Set new highlight + highlightedsector = s; + + // Render highlighted item + if ((highlightedsector != null) && !highlightedsector.IsDisposed) + renderer.PlotSector(highlightedsector, General.Colors.Highlight); + + // Done + renderer.Finish(); + } + + UpdateOverlay(); + renderer.Present(); + */ + General.Interface.RedrawDisplay(); + + // Show highlight info + if ((highlightedsector != null) && !highlightedsector.IsDisposed) + General.Interface.ShowSectorInfo(highlightedsector); + else + General.Interface.HideInfo(); + } + + // This selectes or deselects a sector + protected void SelectSector(Sector s, bool selectstate) + { + bool selectionchanged = false; + + if (!s.IsDisposed) + { + // Select the sector? + if (selectstate && !s.Selected) + { + s.Selected = true; + selectionchanged = true; + } + // Deselect the sector? + else if (!selectstate && s.Selected) + { + s.Selected = false; + selectionchanged = true; + } + + // Selection changed? + if (selectionchanged) + { + // Make update lines selection + foreach (Sidedef sd in s.Sidedefs) + { + bool front, back; + if (sd.Line.Front != null) front = sd.Line.Front.Sector.Selected; else front = false; + if (sd.Line.Back != null) back = sd.Line.Back.Sector.Selected; else back = false; + sd.Line.Selected = front | back; + } + + //mxd. Also (de)select things? + if (General.Interface.AltState) + { + foreach (Thing t in General.Map.ThingsFilter.VisibleThings) + { + t.DetermineSector(); + if (t.Sector != s) continue; + t.Selected = s.Selected; + } + } + } + } + } + + public void ResetHighlightedSector() + { + HighlightSector(null); + } + + // Selection + protected override void OnSelectBegin() + { + // Item highlighted? + if(highlightedslope != null) + { + // Flip selection + highlightedslope.Selected = !highlightedslope.Selected; + + updateOverlaySurfaces(); + UpdateOverlay(); + } + + base.OnSelectBegin(); + } + + // End selection + protected override void OnSelectEnd() + { + // Not ending from a multi-selection? + if(!selecting) + { + // Item highlighted? + if (highlightedslope != null) + { + updateOverlaySurfaces(); + UpdateOverlay(); + } + + if (highlightedsector != null) + { + if (!contextmenuclosing) + { + SelectSector(highlightedsector, !highlightedsector.Selected); + + updateOverlaySurfaces(); + General.Interface.RedrawDisplay(); + } + } + + contextmenuclosing = false; + } + + base.OnSelectEnd(); + } + + // Done editing + protected override void OnEditEnd() + { + base.OnEditEnd(); + + if (dragging) return; + + if (highlightedslope != null) + { + SlopeVertex sv = highlightedslope; + + List vertices = GetSelectedSlopeVertices(); + + if (!vertices.Contains(highlightedslope)) + vertices.Add(highlightedslope); + + SlopeVertexEditForm svef = new SlopeVertexEditForm(); + svef.Setup(vertices); + + DialogResult result = svef.ShowDialog((Form)General.Interface); + + if (result == DialogResult.OK) + { + General.Map.IsChanged = true; + + BuilderPlug.Me.UpdateSlopes(); + } + + highlightedslope = null; + } + else if(highlightedsector != null) + { + if (General.Map.Map.SelectedSectorsCount == 0) + { + BuilderPlug.Me.MenusForm.AddSectorsContextMenu.Tag = new List() { highlightedsector }; + } + else + { + BuilderPlug.Me.MenusForm.AddSectorsContextMenu.Tag = General.Map.Map.GetSelectedSectors(true).ToList(); + } + + BuilderPlug.Me.MenusForm.AddSectorsContextMenu.Show(Cursor.Position); + } + + updateOverlaySurfaces(); + UpdateOverlay(); + + General.Interface.RedrawDisplay(); + } + + //Build a list of the closest svs, that share the same distance away from the mouse cursor + private List GetVertexStack() + { + List stack = new List(); + float d, last = float.MaxValue; + + foreach(SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) { + foreach(SlopeVertex sv in svg.Vertices) + { + d = Vector2D.Distance(sv.Pos, mousemappos); + if (d <= BuilderModes.BuilderPlug.Me.HighlightRange / renderer.Scale) { + if (d > last) + continue; //discard + else if (d < last) + stack.Clear(); + + stack.Add(sv); + last = d; + } + } + } + + return stack; + } + + // Mouse moves + public override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (selectpressed && !editpressed && !selecting) + { + // Check if moved enough pixels for multiselect + Vector2D delta = mousedownpos - mousepos; + if ((Math.Abs(delta.x) > 2) || (Math.Abs(delta.y) > 2)) + { + // Start multiselecting + StartMultiSelection(); + } + } + else if(e.Button == MouseButtons.None) + { + SlopeVertex oldhighlight = highlightedslope; + Sector oldhighlightedsector = highlightedsector; + + //select the closest handle within grabbing distance + List stack = GetVertexStack(); + if (stack.Count > 0) { + SlopeVertex sv = stack[0]; + if (sv != highlightedslope) + { + //if the "closest" handle is the same distance away as the already highlighted handle, then do nothing + if (highlightedslope == null || (Vector2D.Distance(sv.Pos, mousemappos) != Vector2D.Distance(highlightedslope.Pos, mousemappos))) { + highlightedslope = sv; + } + } + } else { + //nothing within distance, so reset the highlight + highlightedslope = null; + } + + // If no slope vertex is highlighted, check if a sector should be + if (highlightedslope == null) + { + // Find the nearest linedef within highlight range + Linedef l = General.Map.Map.NearestLinedef(mousemappos); + if (l != null) + { + // Check on which side of the linedef the mouse is + float side = l.SideOfLine(mousemappos); + if (side > 0) + { + // Is there a sidedef here? + if (l.Back != null) + { + // Highlight if not the same + if (l.Back.Sector != highlightedsector) HighlightSector(l.Back.Sector); + } + else + { + // Highlight nothing + if (highlightedsector != null) HighlightSector(null); + } + } + else + { + // Is there a sidedef here? + if (l.Front != null) + { + // Highlight if not the same + if (l.Front.Sector != highlightedsector) HighlightSector(l.Front.Sector); + } + else + { + // Highlight nothing + if (highlightedsector != null) HighlightSector(null); + } + } + } + } + else + { + HighlightSector(null); + } + + if (highlightedslope != oldhighlight) + { + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + } + else if (dragging && highlightedslope != null) + { + Vector2D newpos = SnapToNearest(mousemappos); + Vector2D offset = highlightedslope.Pos - newpos; + + foreach (SlopeVertex sl in GetSelectedSlopeVertices()) + sl.Pos -= offset; + + highlightedslope.Pos = newpos; + + General.Map.IsChanged = true; + + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + else if (selecting) + { + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + } + + // Mouse leaves + public override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + + // Highlight nothing + highlightedslope = null; + } + + public override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + if (e.Alt) + { + General.Interface.RedrawDisplay(); + } + } + + public override void OnKeyUp(KeyEventArgs e) + { + base.OnKeyUp(e); + + if (!e.Alt) + { + General.Interface.RedrawDisplay(); + } + } + + // Mouse wants to drag + protected override void OnDragStart(MouseEventArgs e) + { + base.OnDragStart(e); + + if (e.Button == MouseButtons.Right) + { + dragging = true; + dragstartmappos = mousemappos; + + oldpositions = new List(); + + foreach(SlopeVertex sl in GetSelectedSlopeVertices()) + if(sl.Selected) + oldpositions.Add(sl.Pos); + + + if(highlightedslope != null) + oldpositions.Add(highlightedslope.Pos); + } + } + //retrieves the current mouse position on the grid, snapped as necessary + private Vector2D SnapToNearest(Vector2D vm) + { + float vrange = 20f / renderer.Scale; + bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; //allow temporary disable of snap by holding shift + + if (General.Interface.AutoMerge) //only snap to geometry if the option is enabled + { + // Try the nearest slope vertex + SlopeVertex nh = NearestSlopeVertexSquareRange(vm, vrange); + if (nh != null) + return nh.Pos; + + // Try the nearest map vertex + Vertex nv = General.Map.Map.NearestVertexSquareRange(vm, vrange); + if (nv != null) + return nv.Position; + + // Try the nearest linedef + Linedef nl = General.Map.Map.NearestLinedefRange(vm, vrange); + if (nl != null) + { + // Snap to grid? + if (snaptogrid) + { + // Get grid intersection coordinates + List coords = nl.GetGridIntersections(); + + // Find nearest grid intersection + bool found = false; + float found_distance = float.MaxValue; + Vector2D found_coord = new Vector2D(); + foreach (Vector2D v in coords) + { + Vector2D delta = vm - v; + if (delta.GetLengthSq() < found_distance) + { + found_distance = delta.GetLengthSq(); + found_coord = v; + found = true; + } + } + + if (found) + return found_coord; + } + else + { + return nl.NearestOnLine(vm); + } + } + } + + //Just get the current mouse location instead + if (snaptogrid) + return General.Map.Grid.SnappedToGrid(vm); + return vm; + } + + /// This finds the thing closest to the specified position. + public SlopeVertex NearestSlopeVertexSquareRange(Vector2D pos, float maxrange) + { + List verts = GetUnSelectedSlopeVertices(); + if (highlightedslope != null) + verts.Remove(highlightedslope); + + return NearestSlopeVertexSquareRange(verts, pos, maxrange); + } + + /// This finds the slope vertex closest to the specified position. + public SlopeVertex NearestSlopeVertexSquareRange(ICollection selection, Vector2D pos, float maxrange) + { + RectangleF range = RectangleF.FromLTRB(pos.x - maxrange, pos.y - maxrange, pos.x + maxrange, pos.y + maxrange); + SlopeVertex closest = null; + float distance = float.MaxValue; + + // Go for all vertices in selection + foreach (SlopeVertex v in selection) + { + float px = v.Pos.x; + float py = v.Pos.y; + + //mxd. Within range? + if ((v.Pos.x < range.Left) || (v.Pos.x > range.Right) + || (v.Pos.y < range.Top) || (v.Pos.y > range.Bottom)) + continue; + + // Close than previous find? + float d = Math.Abs(px - pos.x) + Math.Abs(py - pos.y); + if (d < distance) + { + // This one is closer + closest = v; + distance = d; + } + } + + // Return result + return closest; + } + + // Mouse wants to drag + protected override void OnDragStop(MouseEventArgs e) + { + base.OnDragStop(e); + + General.Map.UndoRedo.CreateUndo("Drag slope vertex"); + + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + General.Map.Map.Update(); + + BuilderPlug.Me.UpdateSlopes(); + + dragging = false; + } + + + // This is called wheh selection ends + protected override void OnEndMultiSelection() + { + bool selectionvolume = ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)); + + if(BuilderPlug.Me.AutoClearSelection && !selectionvolume) + General.Map.Map.ClearSelectedThings(); + + if(selectionvolume) + { + if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect) + { + // Go for all slope vertices + foreach (SlopeVertex sl in GetAllSlopeVertices()) + { + sl.Selected |= ((sl.Pos.x >= selectionrect.Left) && + (sl.Pos.y >= selectionrect.Top) && + (sl.Pos.x <= selectionrect.Right) && + (sl.Pos.y <= selectionrect.Bottom)); + } + } + else + { + // Go for all slope vertices + foreach (SlopeVertex sl in GetAllSlopeVertices()) + { + sl.Selected |= ((sl.Pos.x >= selectionrect.Left) && + (sl.Pos.y >= selectionrect.Top) && + (sl.Pos.x <= selectionrect.Right) && + (sl.Pos.y <= selectionrect.Bottom)); + } + } + } + + base.OnEndMultiSelection(); + + // Clear overlay + if(renderer.StartOverlay(true)) renderer.Finish(); + + // Redraw + General.Interface.RedrawDisplay(); + } + + // This is called when the selection is updated + protected override void OnUpdateMultiSelection() + { + base.OnUpdateMultiSelection(); + + UpdateOverlay(); + } + + public override bool OnCopyBegin() + { + copyslopevertexgroups = new List(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + bool copy = false; + + // Check if the current SVG has to be copied + foreach (SlopeVertex sv in svg.Vertices) + { + if (sv.Selected) + { + copy = true; + break; + } + } + + if (copy) + { + List newsv = new List(); + + foreach (SlopeVertex sv in svg.Vertices) + newsv.Add(new SlopeVertex(sv.Pos, sv.Z)); + + // Use -1 for id, since a real id will be assigned when pasting + copyslopevertexgroups.Add(new SlopeVertexGroup(-1, newsv)); + } + } + + return true; + } + + public override bool OnPasteBegin(PasteOptions options) + { + if (copyslopevertexgroups == null || copyslopevertexgroups.Count == 0) + return false; + + // Unselect all slope vertices, so the pasted vertices can be selected + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + svg.SelectVertices(false); + + float l = copyslopevertexgroups[0].Vertices[0].Pos.x; + float r = copyslopevertexgroups[0].Vertices[0].Pos.x; + float t = copyslopevertexgroups[0].Vertices[0].Pos.y; + float b = copyslopevertexgroups[0].Vertices[0].Pos.y; + + // Find the outer dimensions of all SVGs to paste + foreach (SlopeVertexGroup svg in copyslopevertexgroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + if (sv.Pos.x < l) l = sv.Pos.x; + if (sv.Pos.x > r) r = sv.Pos.x; + if (sv.Pos.y > t) t = sv.Pos.y; + if (sv.Pos.y < b) b = sv.Pos.y; + } + } + + Vector2D center = new Vector2D(l + ((r - l) / 2), b + ((t - b) / 2)); + Vector2D diff = center - General.Map.Grid.SnappedToGrid(mousemappos); + + foreach (SlopeVertexGroup svg in copyslopevertexgroups) + { + int id; + List newsv = new List(); + + foreach (SlopeVertex sv in svg.Vertices) + { + newsv.Add(new SlopeVertex(new Vector2D(sv.Pos.x - diff.x, sv.Pos.y - diff.y), sv.Z)); + } + + SlopeVertexGroup newsvg = BuilderPlug.Me.AddSlopeVertexGroup(newsv, out id); + newsvg.SelectVertices(true); + } + + // Redraw the display, so that pasted SVGs are shown immediately + General.Interface.RedrawDisplay(); + + // Don't go into the standard process for pasting, so tell the core that + // pasting should not proceed + return false; + } + + public List GetSelectedSlopeVertices() + { + List selected = new List(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + if (sv.Selected) + selected.Add(sv); + } + } + + return selected; + } + + public List GetUnSelectedSlopeVertices() + { + List notselected = new List(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + if (!sv.Selected) + notselected.Add(sv); + } + } + + return notselected; + } + + public List GetAllSlopeVertices() + { + List selected = new List(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + selected.Add(sv); + } + } + + return selected; + } + + public List GetSelectedSlopeVertexGroups() + { + List svgs = new List(); + + foreach (SlopeVertex sv in GetSelectedSlopeVertices()) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(sv); + + if (!svgs.Contains(svg)) + svgs.Add(svg); + } + + return svgs; + } + + #endregion + + #region ================== Actions + + [BeginAction("drawfloorslope")] + public void DrawFloorSlope() + { + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = true; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to floor"); + } + + [BeginAction("drawceilingslope")] + public void DrawCeilingSlope() + { + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = true; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to ceiling"); + } + + [BeginAction("drawfloorandceilingslope")] + public void DrawFloorAndCeilingSlope() + { + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = true; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to floor and ceiling"); + } + + [BeginAction("threedflipslope")] + public void FlipSlope() + { + if (highlightedslope == null) + return; + + MessageBox.Show("Flipping temporarily removed"); + + /* + if (highlightedslope.IsOrigin) + { + origin = highlightedslope.ThreeDFloor.Slope.Origin + highlightedslope.ThreeDFloor.Slope.Direction; + direction = highlightedslope.ThreeDFloor.Slope.Direction * (-1); + } + else + { + origin = highlightedslope.ThreeDFloor.Slope.Origin + highlightedslope.ThreeDFloor.Slope.Direction; + direction = highlightedslope.ThreeDFloor.Slope.Direction * (-1); + } + + highlightedslope.ThreeDFloor.Slope.Origin = origin; + highlightedslope.ThreeDFloor.Slope.Direction = direction; + + highlightedslope.ThreeDFloor.Rebuild = true; + + BuilderPlug.ProcessThreeDFloors(new List { highlightedslope.ThreeDFloor }, highlightedslope.ThreeDFloor.TaggedSectors); + + UpdateSlopeObjects(); + + // Redraw + General.Interface.RedrawDisplay(); + */ + } + + // This clears the selection + [BeginAction("clearselection", BaseAction = true)] + public void ClearSelection() + { + int numselected = 0; + // Clear selection + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + if (sv.Selected) + { + sv.Selected = false; + numselected++; + } + + } + } + + // Clear selected sectors when no SVGs are selected + if (numselected == 0) + General.Map.Map.ClearAllSelected(); + + // Redraw + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + + + [BeginAction("deleteitem", BaseAction = true)] + public void DeleteItem() + { + // Make list of selected things + List selected = new List(GetSelectedSlopeVertices()); + + if(highlightedslope != null) + { + selected.Add(highlightedslope); + } + + // Anything to do? + if(selected.Count > 0) + { + List groups = new List(); + + General.Map.UndoRedo.CreateUndo("Delete slope"); + + foreach (SlopeVertex sv in selected) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(sv); + + if (!groups.Contains(svg)) + groups.Add(svg); + } + + foreach (SlopeVertexGroup svg in groups) + { + svg.RemovePlanes(); + svg.RemoveUndoRedoUDMFFields(BuilderPlug.Me.SlopeDataSector); + + BuilderPlug.Me.SlopeVertexGroups.Remove(svg); + } + + General.Map.IsChanged = true; + + // Invoke a new mousemove so that the highlighted item updates + MouseEventArgs e = new MouseEventArgs(MouseButtons.None, 0, (int)mousepos.x, (int)mousepos.y, 0); + OnMouseMove(e); + + // Redraw screen + General.Interface.RedrawDisplay(); + } + } + + + [BeginAction("cyclehighlighted3dfloorup")] + public void CycleHighlighted3DFloorUp() + { + if (highlightedslope == null) + return; + List stack = GetVertexStack(); + if (stack.Count == 0) + return; + + int idx = stack.IndexOf(highlightedslope) + 1; + if (idx >= stack.Count) + idx = 0; + highlightedslope = stack[idx]; + + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + + [BeginAction("cyclehighlighted3dfloordown")] + public void CycleHighlighted3DFloorDown() + { + if (highlightedslope == null) + return; + List stack = GetVertexStack(); + if (stack.Count == 0) + return; + + int idx = stack.IndexOf(highlightedslope) - 1; + if (idx < 0) + idx = stack.Count - 1; + highlightedslope = stack[idx]; + + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/SlopeVertex.cs b/Source/Plugins/3DFloorMode/SlopeVertex.cs new file mode 100644 index 00000000..bb755f60 --- /dev/null +++ b/Source/Plugins/3DFloorMode/SlopeVertex.cs @@ -0,0 +1,99 @@ +#region ================== Namespaces + +using System; +using System.Reflection; +using System.Collections.Generic; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Types; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class SlopeVertex + { + #region ================== Variables + + // private Vector2D pos; + private float x; + private float y; + private float z; + private bool selected; + + #endregion + + #region ================== Constructors + + public SlopeVertex(Sector sector, int svgid, int vertexid) + { + string identifier; + List list = new List { "x", "y", "z" }; + Type type = typeof(SlopeVertex); + + this.x = 0; + this.y = 0; + this.z = 0; + this.selected = false; + + // Read the x, y and z values + foreach (string str in list) + { + identifier = String.Format("user_svg{0}_v{1}_{2}", svgid, vertexid, str); + + // Use reflection to set the variable to the value + type.GetField(str, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, sector.Fields.GetValue(identifier, 0.0f)); + } + } + + public SlopeVertex(Vector2D p, float z) + { + // this.pos = new Vector2D(p); + this.x = p.x; + this.y = p.y; + this.z = z; + this.selected = false; + } + + #endregion + + #region ================== Properties + + public Vector2D Pos { get { return new Vector2D(x, y); } set { x = value.x; y = value.y; } } + public float Z { get { return z; } set { z = value; } } + public bool Selected { get { return selected; } set { selected = value; } } + + #endregion + + #region ================== Methods + + public void StoreInSector(Sector sector, int svgid, int vertexid) + { + string identifier; + + Dictionary dict = new Dictionary + { + { "x", x }, + { "y", y }, + { "z", z } + }; + + // Make sure the field work with undo/redo + sector.Fields.BeforeFieldsChange(); + + // Process the x, y and z fields + foreach (KeyValuePair kvp in dict) + { + identifier = String.Format("user_svg{0}_v{1}_{2}", svgid, vertexid, kvp.Key); + + // Add or update the vertex field + if (sector.Fields.ContainsKey(identifier)) + sector.Fields[identifier] = new UniValue(UniversalType.Float, kvp.Value); + else + sector.Fields.Add(identifier, new UniValue(UniversalType.Float, kvp.Value)); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/SlopeVertexGroup.cs b/Source/Plugins/3DFloorMode/SlopeVertexGroup.cs new file mode 100644 index 00000000..608fa806 --- /dev/null +++ b/Source/Plugins/3DFloorMode/SlopeVertexGroup.cs @@ -0,0 +1,477 @@ +#region ================== Namespaces + +using System; +using System.Reflection; +using System.Runtime.Serialization; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Linq; +using System.Diagnostics; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Types; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class SlopeVertexGroup + { + #region ================== Variables + private List vertices; + private List sectors; + private Dictionary sectorplanes; + private List taggedsectors; // For highlighting 3D floors + private int id; + private int height; + private Vertex anchorvertex; + private Vector2D anchor; + private bool reposition; + private bool spline; + + #endregion + + #region ================== Enums + + #endregion + + #region ================== Properties + + public List Vertices { get { return vertices; } set { vertices = value; ComputeHeight(); } } + public List Sectors { get { return sectors; } set { sectors = value; } } + public Dictionary SectorPlanes { get { return sectorplanes; } } + public List TaggedSectors { get { return taggedsectors; } set { taggedsectors = value; } } + public int Id { get { return id; } } + public int Height { get { return height; } set { height = value; } } + public bool Reposition { get { return reposition; } set { reposition = value; } } + public bool Spline { get { return spline; }set { spline = value; } } + + #endregion + + #region ================== Constructors + + public SlopeVertexGroup(int id, Sector sector) + { + List list = new List { "floor", "ceiling" }; + Type type = typeof(SlopeVertexGroup); + + this.id = id; + sectors = new List(); + sectorplanes = new Dictionary(); + taggedsectors = new List(); + vertices = new List(); + anchorvertex = null; + + // There will always be at least two slope vertices, so add them here + vertices.Add(new SlopeVertex(sector, id, 0)); + vertices.Add(new SlopeVertex(sector, id, 1)); + + // Check if there's a third slope vertex, and add it if there is + string vertexidentifier = String.Format("user_svg{0}_v2_x", id); + + foreach (KeyValuePair kvp in sector.Fields) + { + if (kvp.Key == vertexidentifier) + { + vertices.Add(new SlopeVertex(sector, id, 2)); + break; + } + } + + // Get reposition value + reposition = sector.Fields.GetValue(String.Format("user_svg{0}_reposition", id), true); + + // Get spline value + spline = sector.Fields.GetValue(String.Format("user_svg{0}_spline", id), false); + + spline = false; + + ComputeHeight(); + FindSectors(); + } + + public SlopeVertexGroup(int id, List vertices) + { + this.vertices = vertices; + this.id = id; + sectors = new List(); + sectorplanes = new Dictionary(); + taggedsectors = new List(); + anchorvertex = null; + height = 0; + + ComputeHeight(); + } + + #endregion + + #region ================== Methods + + public void FindSectors() + { + if (sectors == null) + sectors = new List(); + else + sectors.Clear(); + + if (taggedsectors == null) + taggedsectors = new List(); + else + taggedsectors.Clear(); + + sectorplanes.Clear(); + + foreach (Sector s in General.Map.Map.Sectors) + { + bool onfloor = s.Fields.GetValue("user_floorplane_id", -1) == id; + bool onceiling = s.Fields.GetValue("user_ceilingplane_id", -1) == id; + PlaneType pt = 0; + + if (!onfloor && !onceiling) + continue; + + sectors.Add(s); + + if (onfloor && onceiling) + pt = PlaneType.Floor | PlaneType.Ceiling; + else if (onfloor) + pt = PlaneType.Floor; + else if (onceiling) + pt = PlaneType.Ceiling; + + sectorplanes.Add(s, pt); + + GetTaggesSectors(s, pt); + } + } + + public void RemovePlanes() + { + foreach (Sector s in sectors.ToList()) + { + RemoveSector(s, this.sectorplanes[s]); + } + } + + public void RemoveFromSectors() + { + foreach (Sector s in sectors.ToList()) + { + RemoveSector(s, PlaneType.Floor); + RemoveSector(s, PlaneType.Ceiling); + } + } + + private void GetTaggesSectors(Sector s, PlaneType pt) + { + // Check if the current sector is a 3D floor control sector. If that's the case also store the + // tagged sector(s). They will be used for highlighting in slope mode + foreach (Sidedef sd in s.Sidedefs) + { + if (sd.Line.Action == 160) + { + foreach (Sector ts in General.Map.Map.GetSectorsByTag(sd.Line.Args[0])) + { + if (!taggedsectors.Contains(ts)) + taggedsectors.Add(ts); + + if(!sectorplanes.ContainsKey(ts)) + sectorplanes.Add(ts, pt); + } + } + } + } + + public void AddSector(Sector s, PlaneType pt) + { + if (sectorplanes.ContainsKey(s)) + { + pt |= sectorplanes[s]; + sectorplanes.Remove(s); + } + + if (sectors.Contains(s)) + sectors.Remove(s); + + sectorplanes.Add(s, pt); + sectors.Add(s); + + GetTaggesSectors(s, pt); + + ApplyToSectors(); + } + + public void RemoveSector(Sector s, PlaneType pt) + { + Debug.WriteLine("Removing from Sector " + s.Index.ToString() + ": " + pt.ToString()); + + if (sectorplanes.ContainsKey(s)) + { + if (sectors.Contains(s) && sectorplanes[s] == pt) + { + sectors.Remove(s); + sectorplanes.Remove(s); + } + else + sectorplanes[s] &= ~pt; + } + + if ((pt & PlaneType.Floor) == PlaneType.Floor) + { + s.FloorSlope = new Vector3D(); + s.FloorSlopeOffset = 0; + s.Fields.Remove("user_floorplane_id"); + } + + if ((pt & PlaneType.Ceiling) == PlaneType.Ceiling) + { + s.CeilSlope = new Vector3D(); + s.CeilSlopeOffset = 0; + s.Fields.Remove("user_ceilingplane_id"); + } + } + + public void RemoveUndoRedoUDMFFields(Sector s) + { + string fieldname = ""; + string[] comp = new string[] { "x", "y", "z" }; + + if (s == null || s.IsDisposed) + return; + + s.Fields.BeforeFieldsChange(); + + for (int i = 0; i < 3; i++) + { + foreach (string c in comp) + { + fieldname = string.Format("user_svg{0}_v{1}_{2}", id, i, c); + + if (s.Fields.ContainsKey(fieldname)) + s.Fields.Remove(fieldname); + } + } + + // Remove reposition field + fieldname = string.Format("user_svg{0}_reposition", id); + if (s.Fields.ContainsKey(fieldname)) + s.Fields.Remove(fieldname); + } + + public void ApplyToSectors() + { + List removesectors = new List(); + + ComputeHeight(); + + foreach (Sector s in sectors) + { + bool hasplane = false; + + if (sectorplanes.ContainsKey(s) && (sectorplanes[s] & PlaneType.Floor) == PlaneType.Floor) + { + hasplane = true; + + if (s.Fields.ContainsKey("user_floorplane_id")) + s.Fields["user_floorplane_id"] = new UniValue(UniversalType.Integer, id); + else + s.Fields.Add("user_floorplane_id", new UniValue(UniversalType.Integer, id)); + } + else if (s.Fields.ContainsKey("user_floorplane_id") && s.Fields.GetValue("user_floorplane_id", -1) == id) + { + s.Fields.Remove("user_floorplane_id"); + } + + if (sectorplanes.ContainsKey(s) && (sectorplanes[s] & PlaneType.Ceiling) == PlaneType.Ceiling) + { + hasplane = true; + + if (s.Fields.ContainsKey("user_ceilingplane_id")) + s.Fields["user_ceilingplane_id"] = new UniValue(UniversalType.Integer, id); + else + s.Fields.Add("user_ceilingplane_id", new UniValue(UniversalType.Integer, id)); + } + else if (s.Fields.ContainsKey("user_ceilingplane_id") && s.Fields.GetValue("user_ceilingplane_id", -1) == id) + { + s.Fields.Remove("user_ceilingplane_id"); + } + + if (!hasplane) + removesectors.Add(s); + } + + foreach (Sector s in removesectors) + sectors.Remove(s); + + foreach (Sector s in sectors) + BuilderPlug.Me.UpdateSlopes(s); + } + + public void StoreInSector(Sector sector) + { + // Make sure the field work with undo/redo + sector.Fields.BeforeFieldsChange(); + + // Also store all slope vertices in the sector + for (int i = 0; i < vertices.Count; i++) + vertices[i].StoreInSector(sector, id, i); + + string identifier = String.Format("user_svg{0}_reposition", id); + + // Add, update, or delete the reposition field + if (reposition) + { + //default action + if (sector.Fields.ContainsKey(identifier)) + sector.Fields.Remove(identifier); + } + else + { + if (sector.Fields.ContainsKey(identifier)) + sector.Fields[identifier] = new UniValue(UniversalType.Boolean, reposition); + else + sector.Fields.Add(identifier, new UniValue(UniversalType.Boolean, reposition)); + } + + // Spline + identifier = String.Format("user_svg{0}_spline", id); + + if (!spline && sector.Fields.ContainsKey(identifier)) + sector.Fields.Remove(identifier); + else if (spline) + { + if (sector.Fields.ContainsKey(identifier)) + sector.Fields[identifier] = new UniValue(UniversalType.Boolean, spline); + else + sector.Fields.Add(identifier, new UniValue(UniversalType.Boolean, spline)); + } + } + + public void SelectVertices(bool select) + { + foreach (SlopeVertex sv in vertices) + sv.Selected = select; + } + + public bool GetAnchor() + { + anchorvertex = null; + + if (sectors.Count == 0) + return false; + + // Try to find a sector that contains a SV + /* + foreach (Sector s in sectors) + { + foreach (SlopeVertex sv in vertices) + { + if (s.Intersect(sv.Pos)) + { + anchorvertex = s.Sidedefs.First().Line.Start; + anchor = new Vector2D(anchorvertex.Position); + return true; + } + } + } + */ + + // Just grab the next best vertex + foreach (Sector s in sectors) + { + foreach (Sidedef sd in s.Sidedefs) + { + anchorvertex = sd.Line.Start; + anchor = new Vector2D(anchorvertex.Position); + return true; + } + } + + return false; + } + + public void RepositionByAnchor() + { + if (anchorvertex == null || !reposition) + return; + + Vector2D diff = anchorvertex.Position - anchor; + + if (diff.x == 0.0f && diff.y == 0.0f) + return; + + foreach (SlopeVertex sv in vertices) + { + sv.Pos += diff; + } + + anchorvertex = null; + } + + public void ComputeHeight() + { + List sp = new List(); + + for (int i = 0; i < vertices.Count; i++) + { + sp.Add(new Vector3D(vertices[i].Pos.x, vertices[i].Pos.y,vertices[i].Z)); + } + + if (vertices.Count == 2) + { + float z = sp[0].z; + Line2D line = new Line2D(sp[0], sp[1]); + Vector3D perpendicular = line.GetPerpendicular(); + + Vector2D v = sp[0] + perpendicular; + + sp.Add(new Vector3D(v.x, v.y, z)); + } + + Plane p = new Plane(sp[0], sp[1], sp[2], true); + + float fheight = p.GetZ(GetCircumcenter(sp)); + + // If something went wrong with computing the height use the height + // of the first vertex as a workaround + if (float.IsNaN(fheight)) + height = Convert.ToInt32(sp[0].z); + else + height = Convert.ToInt32(fheight); + } + + private Vector2D GetCircumcenter(List points) + { + float u_ray; + + Line2D line1 = new Line2D(points[0], points[1]); + Line2D line2 = new Line2D(points[2], points[0]); + + // Perpendicular bisectors + Line2D bisector1 = new Line2D(line1.GetCoordinatesAt(0.5f), line1.GetCoordinatesAt(0.5f) + line1.GetPerpendicular()); + Line2D bisector2 = new Line2D(line2.GetCoordinatesAt(0.5f), line2.GetCoordinatesAt(0.5f) + line2.GetPerpendicular()); + + bisector1.GetIntersection(bisector2, out u_ray); + + return bisector1.GetCoordinatesAt(u_ray); + } + + public bool VerticesAreValid() + { + if (vertices.Count == 2 && vertices[0].Pos == vertices[1].Pos) + return false; + + if (vertices.Count == 3) + { + float side = Line2D.GetSideOfLine(vertices[0].Pos, vertices[1].Pos, vertices[3].Pos); + + if (side == 0.0f) + return false; + } + + return true; + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/ThreeDFloor.cs b/Source/Plugins/3DFloorMode/ThreeDFloor.cs new file mode 100644 index 00000000..10ecad79 --- /dev/null +++ b/Source/Plugins/3DFloorMode/ThreeDFloor.cs @@ -0,0 +1,351 @@ +#region ================== Copyright (c) 2014 Boris Iwanski + +/* + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class ThreeDFloor + { + private Sector sector; + private List taggedsectors; + private List sectorstotag; + private List sectorstountag; + private string bordertexture; + private string topflat; + private string bottomflat; + private int type; + private int flags; + private int alpha; + private int brightness; + private int topheight; + private int bottomheight; + private bool isnew; + private bool rebuild; + private int udmftag; + private List tags; + + public static Rectangle controlsectorarea = new Rectangle(-512, 512, 512, -512); + + public Sector Sector { get { return sector; } } + public List TaggedSectors { get { return taggedsectors; } set { taggedsectors = value; } } + public List SectorsToTag { get { return sectorstotag; } set { sectorstotag = value; } } + public List SectorsToUntag { get { return sectorstountag; } set { sectorstountag = value; } } + public string BorderTexture { get { return bordertexture; } set { bordertexture = value; } } + public string TopFlat { get { return topflat; } set { topflat = value; } } + public string BottomFlat { get { return bottomflat; } set { bottomflat = value; } } + public int Type { get { return type; } set { type = value; } } + public int Flags { get { return flags; } set { flags = value; } } + public int Alpha { get { return alpha; } set { alpha = value; } } + public int Brightness { get { return brightness; }set { brightness = value; } } + public int TopHeight { get { return topheight; } set { topheight = value; } } + public int BottomHeight { get { return bottomheight; } set { bottomheight = value; } } + public bool IsNew { get { return isnew; } set { isnew = value; } } + public bool Rebuild { get { return rebuild; } set { rebuild = value; } } + public int UDMFTag { get { return udmftag; } set { udmftag = value; } } + public List Tags { get { return tags; } set { tags = value; } } + + public ThreeDFloor() + { + sector = null; + taggedsectors = new List(); + topflat = General.Settings.DefaultCeilingTexture; + bottomflat = General.Settings.DefaultFloorTexture; + topheight = General.Settings.DefaultCeilingHeight; + bottomheight = General.Settings.DefaultFloorHeight; + bordertexture = General.Settings.DefaultTexture; + type = 1; + flags = 0; + tags = new List(); + + alpha = 255; + } + + public ThreeDFloor(Sector sector) + { + if (sector == null) + throw new Exception("Sector can't be null"); + + this.sector = sector; + taggedsectors = new List(); + topflat = sector.CeilTexture; + bottomflat = sector.FloorTexture; + topheight = sector.CeilHeight; + bottomheight = sector.FloorHeight; + brightness = sector.Brightness; + tags = new List(); + + foreach (Sidedef sd in sector.Sidedefs) + { + if (sd.Line.Action == 160) + { + bordertexture = sd.MiddleTexture; + udmftag = sd.Line.Args[0]; + type = sd.Line.Args[1]; + flags = sd.Line.Args[2]; + alpha = sd.Line.Args[3]; + + foreach (Sector s in General.Map.Map.GetSectorsByTag(sd.Line.Args[0])) + { + if(!taggedsectors.Contains(s)) + taggedsectors.Add(s); + } + } + } + } + + public void BindTag(int tag) + { + Linedef line = null; + + // try to find an line without an action + foreach (Sidedef sd in sector.Sidedefs) + { + if (sd.Line.Action == 0 && sd.Line.Tag == 0 && line == null) + line = sd.Line; + + // if a line of the control sector already has the tag + // nothing has to be done + if (sd.Line.Args[0] == tag) + { + return; + } + } + + // no lines without an action, so a line has to get split + // find the longest line to split + if (line == null) + { + line = sector.Sidedefs.First().Line; + + foreach (Sidedef sd in sector.Sidedefs) + { + if (sd.Line.Length > line.Length) + line = sd.Line; + } + + // Lines may not have a length of less than 1 after splitting + if (line.Length / 2 < 1) + throw new Exception("Can't split more lines in Sector " + line.Front.Sector.Index.ToString() + "."); + + Vertex v = General.Map.Map.CreateVertex(line.Line.GetCoordinatesAt(0.5f)); + v.SnapToAccuracy(); + + line = line.Split(v); + + General.Map.Map.Update(); + General.Interface.RedrawDisplay(); + } + + line.Action = 160; + line.Args[0] = tag; + line.Args[1] = type; + line.Args[2] = flags; + line.Args[3] = alpha; + } + + public void UpdateGeometry() + { + if (sector == null) + throw new Exception("3D floor has no geometry"); + + sector.CeilHeight = topheight; + sector.FloorHeight = bottomheight; + sector.SetCeilTexture(topflat); + sector.SetFloorTexture(bottomflat); + sector.Brightness = brightness; + sector.Tags = tags; + + foreach (Sidedef sd in sector.Sidedefs) + { + sd.SetTextureMid(bordertexture); + + if (sd.Line.Action == 160) + { + sd.Line.Args[1] = type; + sd.Line.Args[2] = flags; + sd.Line.Args[3] = alpha; + } + } + } + + public bool CreateGeometry(List tagblacklist) + { + List drawnvertices = new List(); + List vertices = new List(); + Vector3D slopetopthingpos = new Vector3D(0, 0, 0); + Vector3D slopebottomthingpos = new Vector3D(0, 0, 0); + Line2D slopeline = new Line2D(0, 0, 0, 0); + + drawnvertices = BuilderPlug.Me.ControlSectorArea.GetNewControlSectorVertices(); + + if (Tools.DrawLines(drawnvertices) == false) + { + General.Interface.DisplayStatus(StatusType.Warning, "Could not draw new sector"); + return false; + } + + sector = General.Map.Map.GetMarkedSectors(true)[0]; + + sector.FloorHeight = bottomheight; + sector.CeilHeight = topheight; + sector.SetFloorTexture(bottomflat); + sector.SetCeilTexture(topflat); + + foreach (Sidedef sd in sector.Sidedefs) + { + sd.Line.Front.SetTextureMid(bordertexture); + } + + if (!sector.Fields.ContainsKey("user_managed_3d_floor")) + sector.Fields.Add("user_managed_3d_floor", new UniValue(UniversalType.Boolean, true)); + + sector.Fields["comment"] = new UniValue(UniversalType.String, "[!]DO NOT DELETE! This sector is managed by the 3D floor plugin."); + + // With multiple tag support in UDMF only one tag is needed, so bind it right away + if (General.Map.UDMF == true) + { + if(isnew) + udmftag = BuilderPlug.Me.ControlSectorArea.GetNewSectorTag(tagblacklist); + + BindTag(udmftag); + } + + // Snap to map format accuracy + General.Map.Map.SnapAllToAccuracy(); + + General.Map.Map.BeginAddRemove(); + //MapSet.JoinVertices(vertices, vertices, false, MapSet.STITCH_DISTANCE); + General.Map.Map.EndAddRemove(); + + // Update textures + General.Map.Data.UpdateUsedTextures(); + + // Update caches + General.Map.Map.Update(); + General.Interface.RedrawDisplay(); + General.Map.IsChanged = true; + + return true; + } + + public void Cleanup() + { + int taggedLines = 0; + + foreach (Sidedef sd in sector.Sidedefs) + { + if (sd.Line.Action == 160 && General.Map.Map.GetSectorsByTag(sd.Line.Args[0]).Count == 0) + { + sd.Line.Action = 0; + + for (int i = 0; i < 5; i++) + sd.Line.Args[i] = 0; + } + + if (sd.Line.Action != 0) + taggedLines++; + } + + if (taggedLines == 0) + { + DeleteControlSector(sector); + } + } + + private void DeleteControlSector(Sector sector) + { + if (sector == null) + return; + + General.Map.Map.BeginAddRemove(); + + // Get all the linedefs + List lines = new List(sector.Sidedefs.Count); + foreach (Sidedef side in sector.Sidedefs) lines.Add(side.Line); + + + // Dispose the sector + sector.Dispose(); + + // Check all the lines + for (int i = lines.Count - 1; i >= 0; i--) + { + // If the line has become orphaned, remove it + if ((lines[i].Front == null) && (lines[i].Back == null)) + { + // Remove line + lines[i].Dispose(); + } + else + { + // If the line only has a back side left, flip the line and sides + if ((lines[i].Front == null) && (lines[i].Back != null)) + { + lines[i].FlipVertices(); + lines[i].FlipSidedefs(); + } + + // Check textures. + if (lines[i].Front.MiddleRequired() && (lines[i].Front.MiddleTexture.Length == 0 || lines[i].Front.MiddleTexture == "-")) + { + if (lines[i].Front.HighTexture.Length > 0 && lines[i].Front.HighTexture != "-") + { + lines[i].Front.SetTextureMid(lines[i].Front.HighTexture); + } + else if (lines[i].Front.LowTexture.Length > 0 && lines[i].Front.LowTexture != "-") + { + lines[i].Front.SetTextureMid(lines[i].Front.LowTexture); + } + } + + // Do we still need high/low textures? + lines[i].Front.RemoveUnneededTextures(false); + + // Update sided flags + lines[i].ApplySidedFlags(); + } + } + + General.Map.Map.EndAddRemove(); + + // Update cache values + General.Map.IsChanged = true; + General.Map.Map.Update(); + + } + + public void DeleteControlSector() + { + DeleteControlSector(sector); + } + } +} diff --git a/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs new file mode 100644 index 00000000..3814af54 --- /dev/null +++ b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs @@ -0,0 +1,1380 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden, 2014 Boris Iwanski + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Linq; +using System.Diagnostics; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using System.Drawing; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.BuilderModes; +using CodeImp.DoomBuilder.BuilderModes.Interface; +using CodeImp.DoomBuilder.Controls; +// using CodeImp.DoomBuilder.GZBuilder.Geometry; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + [EditMode(DisplayName = "3D Floor Mode", + SwitchAction = "threedfloorhelpermode", // Action name used to switch to this mode + ButtonImage = "ThreeDFloorIcon.png", // Image resource name for the button + ButtonOrder = int.MinValue + 501, // Position of the button (lower is more to the left) + ButtonGroup = "000_editing", + UseByDefault = true, + SafeStartMode = false, + Volatile = false)] + + public class ThreeDFloorHelperMode : ClassicMode + { + #region ================== Constants + + #endregion + + #region ================== Variables + + // Highlighted item + protected Sector highlighted; + protected ThreeDFloor highlighted3dfloor; + private Association highlightasso = new Association(); + private FlatVertex[] overlayGeometry; + private FlatVertex[] overlaygeometry3dfloors; + private FlatVertex[] overlaygeometry3dfloors_highlighted; + private FlatVertex[] overlaygeometry3dfloors_selected; + + // Interface + private ThreeDFloorPanel panel; + private Docker docker; + + // Labels + private Dictionary labels; + private Dictionary selected3Dfloorlabels; + private Dictionary unselected3Dfloorlabels; + + List tooltipelements; + + ControlSectorArea.Highlight csahighlight = ControlSectorArea.Highlight.None; + bool dragging = false; + + private List threedfloors; + + #endregion + + #region ================== Properties + + public override object HighlightedObject { get { return highlighted; } } + + #endregion + + #region ================== Constructor / Disposer + + // Constructor + public ThreeDFloorHelperMode() + { + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + } + + // Disposer + public override void Dispose() + { + // Not already disposed? + if(!isdisposed) + { + // Dispose old labels + foreach(KeyValuePair lbl in labels) + foreach(TextLabel l in lbl.Value) l.Dispose(); + + // Dispose base + base.Dispose(); + } + } + + #endregion + + #region ================== Methods + + + + // This makes a CRC for the selection + public int CreateSelectionCRC() + { + CRC crc = new CRC(); + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + crc.Add(orderedselection.Count); + foreach(Sector s in orderedselection) + { + crc.Add(s.FixedIndex); + } + return (int)(crc.Value & 0xFFFFFFFF); + } + + // This sets up new labels + private void SetupLabels() + { + if(labels != null) + { + // Dispose old labels + foreach(KeyValuePair lbl in labels) + foreach(TextLabel l in lbl.Value) l.Dispose(); + } + + // Make text labels for sectors + labels = new Dictionary(General.Map.Map.Sectors.Count); + foreach(Sector s in General.Map.Map.Sectors) + { + // Setup labels + TextLabel[] labelarray = new TextLabel[s.Labels.Count]; + for(int i = 0; i < s.Labels.Count; i++) + { + labelarray[i] = new TextLabel(); + labelarray[i].TransformCoords = true; + labelarray[i].Location = s.Labels[i].position; + labelarray[i].AlignX = TextAlignmentX.Center; + labelarray[i].AlignY = TextAlignmentY.Middle; + labelarray[i].Color = General.Colors.Highlight.WithAlpha(255); + labelarray[i].BackColor = General.Colors.Background.WithAlpha(128); + } + labels.Add(s, labelarray); + } + } + + // This updates the overlay + private void UpdateOverlay() + { + if(renderer.StartOverlay(true)) + { + if (BuilderPlug.Me.UseHighlight) + { + renderer.RenderHighlight(overlayGeometry, General.Colors.Selection.WithAlpha(64).ToInt()); + } + + if (BuilderPlug.Me.UseHighlight && highlighted != null) + { + renderer.RenderHighlight(highlighted.FlatVertices, General.Colors.Highlight.WithAlpha(64).ToInt()); + + if (highlighted3dfloor != null) + { + renderer.RenderHighlight(overlaygeometry3dfloors, General.Colors.ModelWireframe.WithAlpha(64).ToInt()); + + //show the selected sectors in a darker shade + PixelColor darker = General.Colors.ModelWireframe; + darker.r = (byte)(darker.r * 0.5); + darker.g = (byte)(darker.g * 0.5); + darker.b = (byte)(darker.b * 0.5); + renderer.RenderHighlight(overlaygeometry3dfloors_selected, darker.WithAlpha(64).ToInt()); + + //show the highlighted sectors in a lighter shade + PixelColor lighter = General.Colors.ModelWireframe; + lighter.r = (byte)(lighter.r + (0.5 * (255 - lighter.r))); + lighter.g = (byte)(lighter.g + (0.5 * (255 - lighter.g))); + lighter.b = (byte)(lighter.b + (0.5 * (255 - lighter.b))); + renderer.RenderHighlight(overlaygeometry3dfloors_highlighted, lighter.WithAlpha(64).ToInt()); + } + } + + if (BuilderModes.BuilderPlug.Me.ViewSelectionNumbers) + { + // Go for all selected sectors + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + foreach(Sector s in orderedselection) + { + // Render labels + TextLabel[] labelarray = labels[s]; + for(int i = 0; i < s.Labels.Count; i++) + { + TextLabel l = labelarray[i]; + + // Render only when enough space for the label to see + float requiredsize = (l.TextSize.Height / 2) / renderer.Scale; + if(requiredsize < s.Labels[i].radius) renderer.RenderText(l); + } + } + } + + Render3DFloorLabels(unselected3Dfloorlabels); + + if (!BuilderModes.BuilderPlug.Me.ViewSelectionNumbers) + Render3DFloorLabels(selected3Dfloorlabels); + + BuilderPlug.Me.ControlSectorArea.Draw(renderer, csahighlight); + + renderer.Finish(); + } + } + + private void Render3DFloorLabels(Dictionary labelsgroup) + { + foreach (KeyValuePair group in labelsgroup) + { + // Render labels + TextLabel[] labelarray = labels[group.Key]; + for (int i = 0; i < group.Key.Labels.Count; i++) + { + TextLabel l = labelarray[i]; + l.Color = General.Colors.InfoLine; + + // Render only when enough space for the label to see + float requiredsize = (General.Interface.MeasureString(group.Value[0], l.Font).Width / 2) / renderer.Scale; + + if (requiredsize > group.Key.Labels[i].radius) + { + l.Text = group.Value[1]; + } + else + { + l.Text = group.Value[0]; + } + + renderer.RenderText(l); + } + } + } + + // Generates the tooltip for the 3D floors + private void UpdateDocker(Sector s) + { + List tdfs = new List(); + int count = 0; + + // Get all 3D floors that have the currently highlighted sector tagged. Also order them by their vertical position + foreach (ThreeDFloor tdf in threedfloors.Where(o => o.TaggedSectors.Contains(s)).OrderByDescending(o => o.TopHeight)) + tdfs.Add(tdf); + + // Hide all controls if no sector is selected or selected sector has no 3D floors + if (s == null || tdfs.Count == 0) + { + foreach (Control c in tooltipelements) + { + c.Visible = false; + } + + return; + } + + foreach (ThreeDFloor tdf in tdfs) + { + // Add another control if the list if full + if (count >= tooltipelements.Count) + { + var tte = new ThreeDFloorHelperTooltipElementControl(); + panel.flowLayoutPanel1.Controls.Add(tte); + tooltipelements.Add(tte); + } + + General.DisplayZoomedImage(tooltipelements[count].sectorBottomFlat, General.Map.Data.GetFlatImage(tdf.BottomFlat).GetPreview()); + General.DisplayZoomedImage(tooltipelements[count].sectorBorderTexture, General.Map.Data.GetFlatImage(tdf.BorderTexture).GetPreview()); + General.DisplayZoomedImage(tooltipelements[count].sectorTopFlat, General.Map.Data.GetFlatImage(tdf.TopFlat).GetPreview()); + + tooltipelements[count].bottomHeight.Text = tdf.BottomHeight.ToString(); + tooltipelements[count].topHeight.Text = tdf.TopHeight.ToString(); + tooltipelements[count].borderHeight.Text = (tdf.TopHeight - tdf.BottomHeight).ToString(); + + if (tdf == highlighted3dfloor) + // tooltipelements[count].BackColor = General.Colors.ModelWireframe.ToColor(); + tooltipelements[count].Highlighted = true; + else + // tooltipelements[count].BackColor = SystemColors.Control; + tooltipelements[count].Highlighted = false; + + tooltipelements[count].Refresh(); + tooltipelements[count].Visible = true; + + count++; + } + + // Hide superfluous controls + for (; count < tooltipelements.Count; count++) + { + tooltipelements[count].Visible = false; + } + } + + private void updateOverlaySurfaces() + { + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + List vertsList = new List(); + List vertsList_highlighted = new List(); + List vertsList_selected = new List(); + + // Go for all selected sectors + foreach (Sector s in orderedselection) vertsList.AddRange(s.FlatVertices); + overlayGeometry = vertsList.ToArray(); + + if (highlighted3dfloor != null) + { + vertsList = new List(); + vertsList_highlighted = new List(); + vertsList_selected = new List(); + + foreach (Sector s in highlighted3dfloor.TaggedSectors) + { + //bin the verticies so that then can be properly colored + if (s == highlighted) + vertsList_highlighted.AddRange(s.FlatVertices); + else if (s.Selected) + vertsList_selected.AddRange(s.FlatVertices); + else + vertsList.AddRange(s.FlatVertices); + } + + overlaygeometry3dfloors = vertsList.ToArray(); + overlaygeometry3dfloors_highlighted = vertsList_highlighted.ToArray(); + overlaygeometry3dfloors_selected = vertsList_selected.ToArray(); + } + } + + // Support function for joining and merging sectors + private void JoinMergeSectors(bool removelines) + { + // Remove lines in betwen joining sectors? + if(removelines) + { + // Go for all selected linedefs + List selectedlines = new List(General.Map.Map.GetSelectedLinedefs(true)); + foreach(Linedef ld in selectedlines) + { + // Front and back side? + if((ld.Front != null) && (ld.Back != null)) + { + // Both a selected sector, but not the same? + if(ld.Front.Sector.Selected && ld.Back.Sector.Selected && + (ld.Front.Sector != ld.Back.Sector)) + { + // Remove this line + ld.Dispose(); + } + } + } + } + + // Find the first sector that is not disposed + List orderedselection = new List(General.Map.Map.GetSelectedSectors(true)); + Sector first = null; + foreach(Sector s in orderedselection) + if(!s.IsDisposed) { first = s; break; } + + // Join all selected sectors with the first + for(int i = 0; i < orderedselection.Count; i++) + if((orderedselection[i] != first) && !orderedselection[i].IsDisposed) + orderedselection[i].Join(first); + + // Clear selection + General.Map.Map.ClearAllSelected(); + + // Update + General.Map.Map.Update(); + + // Make text labels for sectors + SetupLabels(); + UpdateLabels(); + } + + // This highlights a new item + protected void Highlight(Sector s) + { + bool completeredraw = false; + + // Often we can get away by simply undrawing the previous + // highlight and drawing the new highlight. But if associations + // are or were drawn we need to redraw the entire display. + + // Previous association highlights something? + if((highlighted != null) && (highlighted.Tag > 0)) completeredraw = true; + + // Set highlight association + if (s != null) + { + Vector2D center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); + highlightasso.Set(center, s.Tag, UniversalType.SectorTag); + } + else + highlightasso.Set(new Vector2D(), 0, 0); + + // New association highlights something? + if((s != null) && (s.Tag > 0)) completeredraw = true; + + // Change label color + if((highlighted != null) && !highlighted.IsDisposed) + { + TextLabel[] labelarray = labels[highlighted]; + foreach(TextLabel l in labelarray) l.Color = General.Colors.Selection; + } + + // Change label color + if((s != null) && !s.IsDisposed) + { + TextLabel[] labelarray = labels[s]; + foreach(TextLabel l in labelarray) l.Color = General.Colors.Highlight; + } + + // If we're changing associations, then we + // need to redraw the entire display + if(completeredraw) + { + // Set new highlight and redraw completely + highlighted = s; + highlighted3dfloor = null; + General.Interface.RedrawDisplay(); + } + else + { + // Update display + if(renderer.StartPlotter(false)) + { + // Undraw previous highlight + if((highlighted != null) && !highlighted.IsDisposed) + renderer.PlotSector(highlighted); + + // Set new highlight + highlighted = s; + + // Render highlighted item + if((highlighted != null) && !highlighted.IsDisposed) + renderer.PlotSector(highlighted, General.Colors.Highlight); + + // Done + renderer.Finish(); + } + + UpdateOverlay(); + renderer.Present(); + } + + // Update the panel with the 3D floors + UpdateDocker(s); + + // Show highlight info + if((highlighted != null) && !highlighted.IsDisposed) + General.Interface.ShowSectorInfo(highlighted); + else + General.Interface.HideInfo(); + } + + // This selectes or deselects a sector + protected void SelectSector(Sector s, bool selectstate, bool update) + { + bool selectionchanged = false; + + if(!s.IsDisposed) + { + // Select the sector? + if(selectstate && !s.Selected) + { + s.Selected = true; + selectionchanged = true; + + // Setup labels + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + TextLabel[] labelarray = labels[s]; + foreach(TextLabel l in labelarray) + { + l.Text = orderedselection.Count.ToString(); + l.Color = General.Colors.Selection; + } + } + // Deselect the sector? + else if(!selectstate && s.Selected) + { + s.Selected = false; + selectionchanged = true; + + // Clear labels + TextLabel[] labelarray = labels[s]; + foreach(TextLabel l in labelarray) l.Text = ""; + } + + // Selection changed? + if(selectionchanged) + { + // Make update lines selection + foreach(Sidedef sd in s.Sidedefs) + { + bool front, back; + if(sd.Line.Front != null) front = sd.Line.Front.Sector.Selected; else front = false; + if(sd.Line.Back != null) back = sd.Line.Back.Sector.Selected; else back = false; + sd.Line.Selected = front | back; + } + + // Update all other labels + UpdateLabels(); + } + + if(update) + { + UpdateOverlay(); + renderer.Present(); + } + } + } + + private void UpdateLabels() + { + Update3DFloorLabels(); + + if (BuilderModes.BuilderPlug.Me.ViewSelectionNumbers) + UpdateSelectedLabels(); + } + + // This updates labels from the selected sectors + private void UpdateSelectedLabels() + { + // Go for all labels in all selected sectors + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + int index = 0; + foreach(Sector s in orderedselection) + { + TextLabel[] labelarray = labels[s]; + foreach(TextLabel l in labelarray) + { + // Make sure the text and color are right + int labelnum = index + 1; + l.Text = labelnum.ToString(); + l.Color = General.Colors.Selection; + } + index++; + } + } + + // Update labels for 3D floors + private void Update3DFloorLabels() + { + Dictionary num3dfloors = new Dictionary(); + selected3Dfloorlabels = new Dictionary(); + unselected3Dfloorlabels = new Dictionary(); + + foreach (ThreeDFloor tdf in threedfloors) + { + foreach (Sector s in tdf.TaggedSectors) + { + if (num3dfloors.ContainsKey(s)) + num3dfloors[s]++; + else + num3dfloors.Add(s, 1); + } + } + + foreach (KeyValuePair group in num3dfloors) + { + if (group.Key.Selected) + selected3Dfloorlabels.Add(group.Key, new string[] { group.Value + (group.Value == 1 ? " floor" : " floors"), group.Value.ToString() }); + else + unselected3Dfloorlabels.Add(group.Key, new string[] { group.Value + (group.Value == 1 ? " floor" : " floors"), group.Value.ToString() }); + } + + /* + foreach (Sector s in General.Map.Map.GetSelectedSectors(true)) + { + List tdfs = BuilderPlug.GetThreeDFloors(new List { s }); + + if (tdfs.Count == 0) + selected3Dfloorlabels.Add(s, new string[] { "", "" }); + else + selected3Dfloorlabels.Add(s, new string[] { tdfs.Count + (tdfs.Count == 1 ? " floor" : " floors"), tdfs.Count.ToString() }); + } + + foreach (Sector s in General.Map.Map.GetSelectedSectors(false)) + { + List tdfs = BuilderPlug.GetThreeDFloors(new List { s }); + + if (tdfs.Count == 0) + unselected3Dfloorlabels.Add(s, new string[] { "", "" }); + else + unselected3Dfloorlabels.Add(s, new string[] { tdfs.Count + (tdfs.Count == 1 ? " floor" : " floors"), tdfs.Count.ToString() }); + } + */ + } + + #endregion + + #region ================== Events + + public override void OnHelp() + { + General.ShowHelp("e_sectors.html"); + } + + // Cancel mode + public override void OnCancel() + { + base.OnCancel(); + + // Return to this mode + General.Editing.ChangeMode(new SectorsMode()); + } + + // Mode engages + public override void OnEngage() + { + base.OnEngage(); + + renderer.SetPresentation(Presentation.Standard); + + tooltipelements = new List(); + + // Add docker + panel = new ThreeDFloorPanel(); + docker = new Docker("threedfloorhelper", "3D floors", panel); + General.Interface.AddDocker(docker); + General.Interface.SelectDocker(docker); + + // Add the view selection number button from BuilderModes. Also add a click event handler + // so we can update the labels when the button is pressed + General.Interface.AddButton(BuilderModes.BuilderPlug.Me.MenusForm.ViewSelectionNumbers); + BuilderModes.BuilderPlug.Me.MenusForm.ViewSelectionNumbers.Click += ViewSelectionNumbers_Click; + + General.Interface.AddButton(BuilderPlug.Me.MenusForm.RelocateControlSectors); + + // Convert geometry selection to sectors only + General.Map.Map.ConvertSelection(SelectionType.Sectors); + + // Make text labels for sectors + SetupLabels(); + + // Update + UpdateLabels(); + updateOverlaySurfaces(); + UpdateOverlay(); + } + + void ViewSelectionNumbers_Click(object sender, EventArgs e) + { + UpdateLabels(); + + OnRedrawDisplay(); + } + + // Mode disengages + public override void OnDisengage() + { + base.OnDisengage(); + + // Remove docker + General.Interface.RemoveDocker(docker); + + // Remove the button and event handler for view selection numbers + General.Interface.RemoveButton(BuilderModes.BuilderPlug.Me.MenusForm.ViewSelectionNumbers); + BuilderModes.BuilderPlug.Me.MenusForm.ViewSelectionNumbers.Click -= ViewSelectionNumbers_Click; + + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.RelocateControlSectors); + + // Keep only sectors selected + General.Map.Map.ClearSelectedLinedefs(); + + // Going to EditSelectionMode? + if(General.Editing.NewMode is EditSelectionMode) + { + // Not pasting anything? + EditSelectionMode editmode = (General.Editing.NewMode as EditSelectionMode); + if(!editmode.Pasting) + { + // No selection made? But we have a highlight! + if((General.Map.Map.GetSelectedSectors(true).Count == 0) && (highlighted != null)) + { + // Make the highlight the selection + SelectSector(highlighted, true, false); + } + } + } + + BuilderPlug.Me.ControlSectorArea.SaveConfig(); + + // Hide highlight info + General.Interface.HideInfo(); + } + + // This redraws the display + public override void OnRedrawDisplay() + { + renderer.RedrawSurface(); + + // Render lines and vertices + if(renderer.StartPlotter(true)) + { + renderer.PlotLinedefSet(General.Map.Map.Linedefs); + renderer.PlotVerticesSet(General.Map.Map.Vertices); + if((highlighted != null) && !highlighted.IsDisposed) + { + renderer.PlotSector(highlighted, General.Colors.Highlight); + // BuilderPlug.Me.PlotReverseAssociations(renderer, highlightasso); + } + + renderer.Finish(); + } + + // Render things + if(renderer.StartThings(true)) + { + renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, Presentation.THINGS_HIDDEN_ALPHA); + renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, 1.0f); + renderer.Finish(); + } + + // Render selection + if(renderer.StartOverlay(true)) + { + + // if((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.Me.RenderReverseAssociations(renderer, highlightasso); + if(selecting) RenderMultiSelection(); + + renderer.Finish(); + } + + // Render overlay + UpdateOverlay(); + + renderer.Present(); + } + + // Selection + protected override void OnSelectBegin() + { + // Item highlighted? + if((highlighted != null) && !highlighted.IsDisposed) + { + // Flip selection + SelectSector(highlighted, !highlighted.Selected, true); + + // Update display + if(renderer.StartPlotter(false)) + { + // Redraw highlight to show selection + renderer.PlotSector(highlighted); + renderer.Finish(); + renderer.Present(); + } + } + + base.OnSelectBegin(); + } + + // End selection + protected override void OnSelectEnd() + { + // Not stopping from multiselection? + if(!selecting) + { + // Item highlighted? + if((highlighted != null) && !highlighted.IsDisposed) + { + // Update display + if(renderer.StartPlotter(false)) + { + // Render highlighted item + renderer.PlotSector(highlighted, General.Colors.Highlight); + renderer.Finish(); + renderer.Present(); + } + + // Update overlay + TextLabel[] labelarray = labels[highlighted]; + foreach(TextLabel l in labelarray) l.Color = General.Colors.Highlight; + updateOverlaySurfaces(); + UpdateOverlay(); + renderer.Present(); + } + } + + base.OnSelectEnd(); + } + + // Start editing + protected override void OnEditBegin() + { + // Item highlighted? + if (((highlighted != null) && !highlighted.IsDisposed) || csahighlight == ControlSectorArea.Highlight.Body) + { + // Edit pressed in this mode + editpressed = true; + + if (csahighlight != ControlSectorArea.Highlight.Body) + { + // Highlighted item not selected? + if (!highlighted.Selected && (BuilderPlug.Me.AutoClearSelection || (General.Map.Map.SelectedSectorsCount == 0))) + { + // Make this the only selection + General.Map.Map.ClearSelectedSectors(); + General.Map.Map.ClearSelectedLinedefs(); + SelectSector(highlighted, true, false); + updateOverlaySurfaces(); + General.Interface.RedrawDisplay(); + } + + // Update display + if (renderer.StartPlotter(false)) + { + // Redraw highlight to show selection + renderer.PlotSector(highlighted); + renderer.Finish(); + renderer.Present(); + } + } + } + + base.OnEditBegin(); + } + + // Done editing + protected override void OnEditEnd() + { + // Edit pressed in this mode? + if(editpressed && !dragging) + { + if (csahighlight == ControlSectorArea.Highlight.Body) + { + BuilderPlug.Me.ControlSectorArea.Edit(); + } + else + { + // Anything selected? + ICollection selected = General.Map.Map.GetSelectedSectors(true); + if (selected.Count > 0) + { + if (General.Interface.IsActiveWindow) + { + // Show sector edit dialog + // General.Interface.ShowEditSectors(selected); + DialogResult result = BuilderPlug.Me.ThreeDFloorEditor(); + + if (result == DialogResult.OK) + { + BuilderPlug.ProcessThreeDFloors(BuilderPlug.TDFEW.ThreeDFloors); + General.Map.Map.Update(); + + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + } + + // When a single sector was selected, deselect it now + if (selected.Count == 1) + { + General.Map.Map.ClearSelectedSectors(); + General.Map.Map.ClearSelectedLinedefs(); + } + + SetupLabels(); + UpdateLabels(); + + // Update entire display + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + } + } + } + + editpressed = false; + base.OnEditEnd(); + } + + // Mouse moves + public override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (selectpressed && !editpressed && !selecting) + { + // Check if moved enough pixels for multiselect + Vector2D delta = mousedownpos - mousepos; + if ((Math.Abs(delta.x) > 2) || (Math.Abs(delta.y) > 2)) + { + // Start multiselecting + StartMultiSelection(); + } + } + else if (e.Button == MouseButtons.None) + { + csahighlight = BuilderPlug.Me.ControlSectorArea.CheckHighlight(mousemappos, renderer.Scale); + + if (csahighlight != ControlSectorArea.Highlight.None) + { + switch (csahighlight) + { + case ControlSectorArea.Highlight.OuterTop: + case ControlSectorArea.Highlight.OuterBottom: + General.Interface.SetCursor(Cursors.SizeNS); + break; + case ControlSectorArea.Highlight.OuterLeft: + case ControlSectorArea.Highlight.OuterRight: + General.Interface.SetCursor(Cursors.SizeWE); + break; + case ControlSectorArea.Highlight.OuterTopLeft: + case ControlSectorArea.Highlight.OuterBottomRight: + General.Interface.SetCursor(Cursors.SizeNWSE); + break; + case ControlSectorArea.Highlight.OuterTopRight: + case ControlSectorArea.Highlight.OuterBottomLeft: + General.Interface.SetCursor(Cursors.SizeNESW); + break; + case ControlSectorArea.Highlight.Body: + General.Interface.SetCursor(Cursors.Hand); + break; + } + + Highlight(null); + return; + } + + General.Interface.SetCursor(Cursors.Default); + + // Find the nearest linedef within highlight range + Linedef l = General.Map.Map.NearestLinedef(mousemappos); + if (l != null) + { + // Check on which side of the linedef the mouse is + float side = l.SideOfLine(mousemappos); + if (side > 0) + { + // Is there a sidedef here? + if (l.Back != null) + { + // Highlight if not the same + if (l.Back.Sector != highlighted) Highlight(l.Back.Sector); + } + else + { + // Highlight nothing + Highlight(null); + } + } + else + { + // Is there a sidedef here? + if (l.Front != null) + { + // Highlight if not the same + if (l.Front.Sector != highlighted) Highlight(l.Front.Sector); + } + else + { + // Highlight nothing + Highlight(null); + } + } + } + else + { + // Highlight nothing + Highlight(null); + } + } + else if (dragging && csahighlight != ControlSectorArea.Highlight.None) + { + BuilderPlug.Me.ControlSectorArea.SnapToGrid(csahighlight, mousemappos, renderer.DisplayToMap(mouselastpos)); + Highlight(null); + } + } + + // Mouse leaves + public override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + + // Highlight nothing + Highlight(null); + } + + // Mouse wants to drag + protected override void OnDragStart(MouseEventArgs e) + { + base.OnDragStart(e); + + if(e.Button == MouseButtons.Right) + dragging = true; + + } + + protected override void OnDragStop(MouseEventArgs e) + { + dragging = false; + + BuilderPlug.Me.ControlSectorArea.SaveConfig(); + } + + // This is called wheh selection ends + protected override void OnEndMultiSelection() + { + bool selectionvolume = ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)); + + if(BuilderPlug.Me.AutoClearSelection && !selectionvolume) + { + General.Map.Map.ClearSelectedLinedefs(); + General.Map.Map.ClearSelectedSectors(); + } + + if(selectionvolume) + { + if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect) + { + // Go for all lines + foreach(Linedef l in General.Map.Map.Linedefs) + { + l.Selected |= ((l.Start.Position.x >= selectionrect.Left) && + (l.Start.Position.y >= selectionrect.Top) && + (l.Start.Position.x <= selectionrect.Right) && + (l.Start.Position.y <= selectionrect.Bottom) && + (l.End.Position.x >= selectionrect.Left) && + (l.End.Position.y >= selectionrect.Top) && + (l.End.Position.x <= selectionrect.Right) && + (l.End.Position.y <= selectionrect.Bottom)); + } + } + else + { + // Go for all lines + foreach(Linedef l in General.Map.Map.Linedefs) + { + l.Selected = ((l.Start.Position.x >= selectionrect.Left) && + (l.Start.Position.y >= selectionrect.Top) && + (l.Start.Position.x <= selectionrect.Right) && + (l.Start.Position.y <= selectionrect.Bottom) && + (l.End.Position.x >= selectionrect.Left) && + (l.End.Position.y >= selectionrect.Top) && + (l.End.Position.x <= selectionrect.Right) && + (l.End.Position.y <= selectionrect.Bottom)); + } + } + + // Go for all sectors + foreach(Sector s in General.Map.Map.Sectors) + { + // Go for all sidedefs + bool allselected = true; + foreach(Sidedef sd in s.Sidedefs) + { + if(!sd.Line.Selected) + { + allselected = false; + break; + } + } + + // Sector completely selected? + SelectSector(s, allselected, false); + } + + // Make sure all linedefs reflect selected sectors + foreach(Sidedef sd in General.Map.Map.Sidedefs) + if(!sd.Sector.Selected && ((sd.Other == null) || !sd.Other.Sector.Selected)) + sd.Line.Selected = false; + + updateOverlaySurfaces(); + } + + base.OnEndMultiSelection(); + if(renderer.StartOverlay(true)) renderer.Finish(); + General.Interface.RedrawDisplay(); + } + + // This is called when the selection is updated + protected override void OnUpdateMultiSelection() + { + base.OnUpdateMultiSelection(); + + // Render selection + if(renderer.StartOverlay(true)) + { + RenderMultiSelection(); + renderer.Finish(); + renderer.Present(); + } + } + + // When copying + public override bool OnCopyBegin() + { + // No selection made? But we have a highlight! + if((General.Map.Map.GetSelectedSectors(true).Count == 0) && (highlighted != null)) + { + // Make the highlight the selection + SelectSector(highlighted, true, true); + } + + return base.OnCopyBegin(); + } + + // When undo is used + public override bool OnUndoBegin() + { + // Clear ordered selection + General.Map.Map.ClearAllSelected(); + + return base.OnUndoBegin(); + } + + // When undo is performed + public override void OnUndoEnd() + { + // Get all 3D floors in case th undo did affect them + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + + // Clear labels + SetupLabels(); + UpdateLabels(); + } + + // When redo is used + public override bool OnRedoBegin() + { + // Clear ordered selection + General.Map.Map.ClearAllSelected(); + + return base.OnRedoBegin(); + } + + // When redo is performed + public override void OnRedoEnd() + { + // Get all 3D floors in case th redo did affect them + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + + // Clear labels + SetupLabels(); + UpdateLabels(); + } + + #endregion + + #region ================== Actions + + // This clears the selection + [BeginAction("clearselection", BaseAction = true)] + public void ClearSelection() + { + // Clear selection + General.Map.Map.ClearAllSelected(); + + // Clear labels + foreach (TextLabel[] labelarray in labels.Values) + foreach (TextLabel l in labelarray) l.Text = ""; + + SetupLabels(); + UpdateLabels(); + + updateOverlaySurfaces(); + + // Redraw + General.Interface.RedrawDisplay(); + } + + [BeginAction("cyclehighlighted3dfloorup")] + public void CycleHighlighted3DFloorUp() + { + if (highlighted == null) + return; + + List tdfs = new List(); + + // Get all 3D floors that have the currently highlighted sector tagged. Also order them by their vertical position + foreach (ThreeDFloor tdf in threedfloors.Where(o => o.TaggedSectors.Contains(highlighted)).OrderByDescending(o => o.TopHeight)) + tdfs.Add(tdf); + + if (tdfs.Count == 0) // Nothing to highlight + { + highlighted3dfloor = null; + } + else if (highlighted3dfloor == null) // No 3D floor currently highlighted? Just get the last one + { + highlighted3dfloor = tdfs.Last(); + } + else // Find the currently highlighted 3D floor in the list and take the next one + { + int i; + + for (i = tdfs.Count-1; i >= 0; i--) + { + if (tdfs[i] == highlighted3dfloor) + { + if (i > 0) + { + highlighted3dfloor = tdfs[i - 1]; + break; + } + } + } + + // Beginning of the list was reached, so don't highlight any 3D floor + if (i < 0) + highlighted3dfloor = null; + } + + UpdateDocker(highlighted); + + updateOverlaySurfaces(); + + General.Interface.RedrawDisplay(); + + } + + [BeginAction("cyclehighlighted3dfloordown")] + public void CycleHighlighted3DFloorDown() + { + if (highlighted == null) + return; + + List tdfs = new List(); + + // Get all 3D floors that have the currently highlighted sector tagged. Also order them by their vertical position + foreach (ThreeDFloor tdf in threedfloors.Where(o => o.TaggedSectors.Contains(highlighted)).OrderByDescending(o => o.TopHeight)) + tdfs.Add(tdf); + + if (tdfs.Count == 0) // Nothing to highlight + { + highlighted3dfloor = null; + } + else if (highlighted3dfloor == null) // No 3D floor currently highlighted? Just get the first one + { + highlighted3dfloor = tdfs[0]; + } + else // Find the currently highlighted 3D floor in the list and take the next one + { + int i; + + for (i = 0; i < tdfs.Count; i++) + { + if (tdfs[i] == highlighted3dfloor) + { + if (i < tdfs.Count-1) + { + highlighted3dfloor = tdfs[i + 1]; + break; + } + } + } + + // End of the list was reached, so don't highlight any 3D floor + if (i == tdfs.Count) + highlighted3dfloor = null; + } + + UpdateDocker(highlighted); + + updateOverlaySurfaces(); + + General.Interface.RedrawDisplay(); + } + + [BeginAction("relocate3dfloorcontrolsectors")] + public void RelocateControlSectors() + { + List positions; + + if (threedfloors.Count == 0) + { + General.Interface.DisplayStatus(StatusType.Warning, "There are no control sectors to relocate"); + return; + } + + try + { + positions = BuilderPlug.Me.ControlSectorArea.GetRelocatePositions(threedfloors.Count); + } + catch (Exception e) + { + General.Interface.DisplayStatus(StatusType.Warning, e.Message + ". Please increase the size of the control sector area"); + return; + } + + // Some sanity checks + if (positions.Count != threedfloors.Count) + { + General.Interface.DisplayStatus(StatusType.Warning, "Mismatch between number of relocation points and control sectors. Aborted"); + return; + } + + // Control sectors are not allowed to be bigger than what the CSA expects, otherwise sectors might overlap + // Abort relocation if one of the control sectors is too big (that should only happen if the user edited the + // sector manually + foreach (ThreeDFloor tdf in threedfloors) + { + if (tdf.Sector.BBox.Width > BuilderPlug.Me.ControlSectorArea.SectorSize || tdf.Sector.BBox.Height > BuilderPlug.Me.ControlSectorArea.SectorSize) + { + General.Interface.DisplayStatus(StatusType.Warning, string.Format("Control sector {0} exceeds horizontal or vertical dimenstion of {1}. Aborted", tdf.Sector.Index, BuilderPlug.Me.ControlSectorArea.SectorSize)); + return; + } + } + + General.Map.UndoRedo.CreateUndo("Relocate 3D floor control sectors"); + + // Counter for the new positions + int i = 0; + + // Move the control sectors + foreach (ThreeDFloor tdf in threedfloors) + { + Vector2D offset = new Vector2D(tdf.Sector.BBox.Left - positions[i].x, tdf.Sector.BBox.Bottom - positions[i].y); + HashSet vertices = new HashSet(); + + // Get all vertices + foreach (Sidedef sd in tdf.Sector.Sidedefs) + { + vertices.Add(sd.Line.Start); + vertices.Add(sd.Line.End); + } + + foreach (Vertex v in vertices) + v.Move(v.Position - offset); + + i++; + } + + General.Map.Map.Update(); + General.Interface.RedrawDisplay(); + } + + [BeginAction("select3dfloorcontrolsector")] + public void Select3DFloorControlSector() + { + //if there is no 3d floor highlighted, then try to select the first one from the top-down, if possible + if (highlighted3dfloor == null) + { + CycleHighlighted3DFloorDown(); + } + + if (highlighted3dfloor == null) + { + General.Interface.DisplayStatus(StatusType.Warning, "You have to highlight a 3D floor to select its control sector"); + return; + } + + SelectSector(highlighted3dfloor.Sector, true, true); + + updateOverlaySurfaces(); + + General.Interface.RedrawDisplay(); + + General.Interface.DisplayStatus(StatusType.Info, String.Format("3D floor control sector selected. {0} sector(s) selected.", General.Map.Map.GetSelectedSectors(true).Count)); + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/ThreeDFloorMode.csproj b/Source/Plugins/3DFloorMode/ThreeDFloorMode.csproj new file mode 100644 index 00000000..dadcd62c --- /dev/null +++ b/Source/Plugins/3DFloorMode/ThreeDFloorMode.csproj @@ -0,0 +1,259 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {88CFD996-027B-4CBE-9828-26B2728B6127} + Library + Properties + ThreeDFloorMode + ThreeDFloorMode + v4.6.1 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + true + full + false + ..\..\..\Build\Plugins\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\..\Build\Plugins\ + TRACE + prompt + 4 + false + + + true + ..\..\..\Build\Plugins\ + DEBUG;TRACE + full + x86 + prompt + false + + + ..\..\..\Build\Plugins\ + TRACE + true + pdbonly + x86 + prompt + false + + + true + ..\..\..\Build\Plugins\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + ..\..\..\Build\Plugins\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + + 3.5 + + + + + 3.5 + + + 3.5 + + + + + + + + + UserControl + + + ThreeDFloorTooltipControl.cs + + + + Form + + + PreferencesForm.cs + + + UserControl + + + ThreeDFloorPanel.cs + + + + UserControl + + + ThreeDFloorControl.cs + + + True + True + Resources.resx + + + + + + + + + Form + + + ControlSectorAreaConfig.cs + + + Form + + + MenusForm.cs + + + Form + + + SlopeDataSectorDialog.cs + + + Form + + + SlopeVertexEditForm.cs + + + Form + + + ThreeDFloorEditorWindow.cs + + + + + ThreeDFloorControl.cs + + + + + PreferencesForm.cs + + + + ThreeDFloorEditorWindow.cs + + + + + ThreeDFloorTooltipControl.cs + + + ThreeDFloorPanel.cs + + + + ControlSectorAreaConfig.cs + + + SlopeVertexEditForm.cs + + + + + + + + + MenusForm.cs + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + SlopeDataSectorDialog.cs + + + + + False + .NET Framework 3.5 SP1 + true + + + + + {818b3d10-f791-4c3f-9af5-bb2d0079b63c} + Builder + False + + + {b859be0f-a992-476d-a642-fa8efe94aaa5} + BuilderEffects + + + {b42d5aa0-f9a6-4234-9c4b-a05b11a64851} + BuilderModes + + + + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.Designer.cs b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.Designer.cs new file mode 100644 index 00000000..db103d37 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.Designer.cs @@ -0,0 +1,161 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ControlSectorAreaConfig + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.lastTag = new CodeImp.DoomBuilder.Controls.NumericTextbox(); + this.firstTag = new CodeImp.DoomBuilder.Controls.NumericTextbox(); + this.useTagRange = new System.Windows.Forms.CheckBox(); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Controls.Add(this.lastTag); + this.groupBox1.Controls.Add(this.firstTag); + this.groupBox1.Controls.Add(this.useTagRange); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(225, 57); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(120, 27); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(27, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Last"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 27); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(26, 13); + this.label1.TabIndex = 3; + this.label1.Text = "First"; + // + // lastTag + // + this.lastTag.AllowDecimal = false; + this.lastTag.AllowNegative = false; + this.lastTag.AllowRelative = false; + this.lastTag.Enabled = false; + this.lastTag.ImeMode = System.Windows.Forms.ImeMode.Off; + this.lastTag.Location = new System.Drawing.Point(153, 24); + this.lastTag.Name = "lastTag"; + this.lastTag.Size = new System.Drawing.Size(62, 20); + this.lastTag.TabIndex = 2; + // + // firstTag + // + this.firstTag.AllowDecimal = false; + this.firstTag.AllowNegative = false; + this.firstTag.AllowRelative = false; + this.firstTag.Enabled = false; + this.firstTag.ImeMode = System.Windows.Forms.ImeMode.Off; + this.firstTag.Location = new System.Drawing.Point(38, 24); + this.firstTag.Name = "firstTag"; + this.firstTag.Size = new System.Drawing.Size(62, 20); + this.firstTag.TabIndex = 1; + // + // useTagRange + // + this.useTagRange.AutoSize = true; + this.useTagRange.Location = new System.Drawing.Point(7, 1); + this.useTagRange.Name = "useTagRange"; + this.useTagRange.Size = new System.Drawing.Size(93, 17); + this.useTagRange.TabIndex = 0; + this.useTagRange.Text = "Use tag range"; + this.useTagRange.UseVisualStyleBackColor = true; + this.useTagRange.CheckedChanged += new System.EventHandler(this.useTagRange_CheckedChanged); + // + // okButton + // + this.okButton.Location = new System.Drawing.Point(47, 75); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 1; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // cancelButton + // + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(128, 75); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 2; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // ControlSectorAreaConfig + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(250, 109); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okButton); + this.Controls.Add(this.groupBox1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Name = "ControlSectorAreaConfig"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Control Sector Area Configuration"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private CodeImp.DoomBuilder.Controls.NumericTextbox firstTag; + private System.Windows.Forms.CheckBox useTagRange; + private CodeImp.DoomBuilder.Controls.NumericTextbox lastTag; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.cs b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.cs new file mode 100644 index 00000000..9dec5fd6 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ControlSectorAreaConfig : Form + { + private ControlSectorArea csa; + + public ControlSectorAreaConfig(ControlSectorArea csa) + { + this.csa = csa; + + InitializeComponent(); + + useTagRange.Checked = csa.UseCustomTagRnage; + firstTag.Text = csa.FirstTag.ToString(); + lastTag.Text = csa.LastTag.ToString(); + } + + private void useTagRange_CheckedChanged(object sender, EventArgs e) + { + if (useTagRange.Checked) + { + firstTag.Enabled = true; + lastTag.Enabled = true; + } + else + { + firstTag.Enabled = false; + lastTag.Enabled = false; + } + } + + private void cancelButton_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void okButton_Click(object sender, EventArgs e) + { + if (useTagRange.Checked && int.Parse(lastTag.Text) < int.Parse(firstTag.Text)) + { + MessageBox.Show("Last tag of range must be bigger than first tag of range", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + csa.UseCustomTagRnage = useTagRange.Checked; + + if (useTagRange.Checked) + { + csa.FirstTag = int.Parse(firstTag.Text); + csa.LastTag = int.Parse(lastTag.Text); + } + + this.DialogResult = DialogResult.OK; + this.Close(); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.resx b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.resx new file mode 100644 index 00000000..19dc0dd8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/MenusForm.Designer.cs b/Source/Plugins/3DFloorMode/Windows/MenusForm.Designer.cs new file mode 100644 index 00000000..aec62a1d --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/MenusForm.Designer.cs @@ -0,0 +1,194 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class MenusForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MenusForm)); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.floorslope = new System.Windows.Forms.ToolStripButton(); + this.ceilingslope = new System.Windows.Forms.ToolStripButton(); + this.floorandceilingslope = new System.Windows.Forms.ToolStripButton(); + this.updateslopes = new System.Windows.Forms.ToolStripButton(); + this.addsectorscontextmenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.addslopeceiling = new System.Windows.Forms.ToolStripMenuItem(); + this.addslopefloor = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.removeslopeceiling = new System.Windows.Forms.ToolStripMenuItem(); + this.removeslopefloor = new System.Windows.Forms.ToolStripMenuItem(); + this.relocatecontrolsectors = new System.Windows.Forms.ToolStripButton(); + this.toolStrip1.SuspendLayout(); + this.addsectorscontextmenu.SuspendLayout(); + this.SuspendLayout(); + // + // toolStrip1 + // + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.floorslope, + this.ceilingslope, + this.floorandceilingslope, + this.updateslopes, + this.relocatecontrolsectors}); + this.toolStrip1.Location = new System.Drawing.Point(0, 0); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(442, 25); + this.toolStrip1.TabIndex = 0; + this.toolStrip1.Text = "toolStrip1"; + // + // floorslope + // + this.floorslope.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.floorslope.Image = global::ThreeDFloorMode.Properties.Resources.Floor; + this.floorslope.ImageTransparentColor = System.Drawing.Color.Magenta; + this.floorslope.Name = "floorslope"; + this.floorslope.Size = new System.Drawing.Size(23, 22); + this.floorslope.Tag = "drawfloorslope"; + this.floorslope.Text = "Apply drawn slope to floor"; + this.floorslope.Click += new System.EventHandler(this.floorslope_Click); + // + // ceilingslope + // + this.ceilingslope.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.ceilingslope.Image = global::ThreeDFloorMode.Properties.Resources.Ceiling; + this.ceilingslope.ImageTransparentColor = System.Drawing.Color.Magenta; + this.ceilingslope.Name = "ceilingslope"; + this.ceilingslope.Size = new System.Drawing.Size(23, 22); + this.ceilingslope.Tag = "drawceilingslope"; + this.ceilingslope.Text = "Apply drawn slope to ceiling"; + this.ceilingslope.Click += new System.EventHandler(this.ceilingslope_Click); + // + // floorandceilingslope + // + this.floorandceilingslope.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.floorandceilingslope.Image = global::ThreeDFloorMode.Properties.Resources.FloorAndCeiling; + this.floorandceilingslope.ImageTransparentColor = System.Drawing.Color.Magenta; + this.floorandceilingslope.Name = "floorandceilingslope"; + this.floorandceilingslope.Size = new System.Drawing.Size(23, 22); + this.floorandceilingslope.Tag = "drawfloorandceilingslope"; + this.floorandceilingslope.Text = "Apply drawn slope to floor and ceiling"; + this.floorandceilingslope.Click += new System.EventHandler(this.floorandceilingslope_Click); + // + // updateslopes + // + this.updateslopes.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.updateslopes.Image = ((System.Drawing.Image)(resources.GetObject("updateslopes.Image"))); + this.updateslopes.ImageTransparentColor = System.Drawing.Color.Magenta; + this.updateslopes.Name = "updateslopes"; + this.updateslopes.Size = new System.Drawing.Size(85, 22); + this.updateslopes.Text = "Update slopes"; + this.updateslopes.Click += new System.EventHandler(this.toolStripButton1_Click); + // + // addsectorscontextmenu + // + this.addsectorscontextmenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.addslopeceiling, + this.addslopefloor, + this.toolStripSeparator1, + this.removeslopeceiling, + this.removeslopefloor}); + this.addsectorscontextmenu.Name = "addsectorscontextmenu"; + this.addsectorscontextmenu.Size = new System.Drawing.Size(216, 98); + this.addsectorscontextmenu.Opening += new System.ComponentModel.CancelEventHandler(this.addsectorscontextmenu_Opening); + this.addsectorscontextmenu.Closing += new System.Windows.Forms.ToolStripDropDownClosingEventHandler(this.addsectorscontextmenu_Closing); + // + // addslopeceiling + // + this.addslopeceiling.Name = "addslopeceiling"; + this.addslopeceiling.Size = new System.Drawing.Size(215, 22); + this.addslopeceiling.Text = "Add slope to ceiling"; + this.addslopeceiling.Click += new System.EventHandler(this.ceilingToolStripMenuItem_Click); + // + // addslopefloor + // + this.addslopefloor.Name = "addslopefloor"; + this.addslopefloor.Size = new System.Drawing.Size(215, 22); + this.addslopefloor.Text = "Add slope to floor"; + this.addslopefloor.Click += new System.EventHandler(this.floorToolStripMenuItem_Click); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(212, 6); + // + // removeslopeceiling + // + this.removeslopeceiling.Name = "removeslopeceiling"; + this.removeslopeceiling.Size = new System.Drawing.Size(215, 22); + this.removeslopeceiling.Text = "Remove slope from ceiling"; + this.removeslopeceiling.Click += new System.EventHandler(this.removeSlopeFromCeilingToolStripMenuItem_Click); + // + // removeslopefloor + // + this.removeslopefloor.Name = "removeslopefloor"; + this.removeslopefloor.Size = new System.Drawing.Size(215, 22); + this.removeslopefloor.Text = "Remove slope from floor"; + this.removeslopefloor.Click += new System.EventHandler(this.removeSlopeFromFloorToolStripMenuItem_Click); + // + // relocatecontrolsectors + // + this.relocatecontrolsectors.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.relocatecontrolsectors.Image = ((System.Drawing.Image)(resources.GetObject("relocatecontrolsectors.Image"))); + this.relocatecontrolsectors.ImageTransparentColor = System.Drawing.Color.Magenta; + this.relocatecontrolsectors.Name = "relocatecontrolsectors"; + this.relocatecontrolsectors.Size = new System.Drawing.Size(137, 22); + this.relocatecontrolsectors.Tag = "relocate3dfloorcontrolsectors"; + this.relocatecontrolsectors.Text = "Relocate control sectors"; + this.relocatecontrolsectors.Click += new System.EventHandler(this.relocatecontrolsectors_Click); + // + // MenusForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(442, 262); + this.Controls.Add(this.toolStrip1); + this.Name = "MenusForm"; + this.Text = "MenusForm"; + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + this.addsectorscontextmenu.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.ToolStripButton floorslope; + private System.Windows.Forms.ToolStripButton ceilingslope; + private System.Windows.Forms.ToolStripButton floorandceilingslope; + private System.Windows.Forms.ToolStripButton updateslopes; + private System.Windows.Forms.ContextMenuStrip addsectorscontextmenu; + private System.Windows.Forms.ToolStripMenuItem addslopefloor; + private System.Windows.Forms.ToolStripMenuItem addslopeceiling; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripMenuItem removeslopeceiling; + private System.Windows.Forms.ToolStripMenuItem removeslopefloor; + private System.Windows.Forms.ToolStripButton relocatecontrolsectors; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/MenusForm.cs b/Source/Plugins/3DFloorMode/Windows/MenusForm.cs new file mode 100644 index 00000000..e7dc6822 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/MenusForm.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.Map; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class MenusForm : Form + { + public ToolStripButton FloorSlope { get { return floorslope; } } + public ToolStripButton CeilingSlope { get { return ceilingslope; } } + public ToolStripButton FloorAndCeilingSlope { get { return floorandceilingslope; } } + public ToolStripButton UpdateSlopes { get { return updateslopes; } } + public ToolStripButton RelocateControlSectors { get { return relocatecontrolsectors; } } + public ContextMenuStrip AddSectorsContextMenu { get { return addsectorscontextmenu; } } + + public MenusForm() + { + InitializeComponent(); + } + + private void InvokeTaggedAction(object sender, EventArgs e) + { + General.Interface.InvokeTaggedAction(sender, e); + } + + private void floorslope_Click(object sender, EventArgs e) + { + if (floorslope.Checked) + return; + + General.Interface.InvokeTaggedAction(sender, e); + } + + private void ceilingslope_Click(object sender, EventArgs e) + { + if (ceilingslope.Checked) + return; + + General.Interface.InvokeTaggedAction(sender, e); + } + + private void floorandceilingslope_Click(object sender, EventArgs e) + { + if (floorandceilingslope.Checked) + return; + + General.Interface.InvokeTaggedAction(sender, e); + } + + private void toolStripButton1_Click(object sender, EventArgs e) + { + BuilderPlug.Me.UpdateSlopes(); + } + + private void floorToolStripMenuItem_Click(object sender, EventArgs e) + { + List svgs = ((SlopeMode)General.Editing.Mode).GetSelectedSlopeVertexGroups(); + + // Can only add sectors to one slope vertex group + if (svgs.Count != 1) + return; + + foreach (Sector s in (List)addsectorscontextmenu.Tag) + { + SlopeVertexGroup rsvg = BuilderPlug.Me.GetSlopeVertexGroup(s); + + if (rsvg != null) + rsvg.RemoveSector(s, PlaneType.Floor); + + svgs[0].AddSector(s, PlaneType.Floor); + BuilderPlug.Me.UpdateSlopes(s); + } + + General.Interface.RedrawDisplay(); + } + + private void removeSlopeFromFloorToolStripMenuItem_Click(object sender, EventArgs e) + { + foreach (Sector s in (List)addsectorscontextmenu.Tag) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(s); + + if (svg != null) + svg.RemoveSector(s, PlaneType.Floor); + } + + General.Interface.RedrawDisplay(); + } + + private void ceilingToolStripMenuItem_Click(object sender, EventArgs e) + { + List svgs = ((SlopeMode)General.Editing.Mode).GetSelectedSlopeVertexGroups(); + + // Can only add sectors to one slope vertex group + if (svgs.Count != 1) + return; + + foreach (Sector s in (List)addsectorscontextmenu.Tag) + { + SlopeVertexGroup rsvg = BuilderPlug.Me.GetSlopeVertexGroup(s); + + if (rsvg != null) + rsvg.RemoveSector(s, PlaneType.Ceiling); + + svgs[0].AddSector(s, PlaneType.Ceiling); + BuilderPlug.Me.UpdateSlopes(s); + } + + General.Interface.RedrawDisplay(); + } + + private void removeSlopeFromCeilingToolStripMenuItem_Click(object sender, EventArgs e) + { + foreach (Sector s in (List)addsectorscontextmenu.Tag) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(s); + + if(svg != null) + svg.RemoveSector(s, PlaneType.Ceiling); + } + + General.Interface.RedrawDisplay(); + } + + private void addsectorscontextmenu_Opening(object sender, CancelEventArgs e) + { + // Disable adding if more than one slope vertex group is selected, + // otherwise enable adding + List svgs = ((SlopeMode)General.Editing.Mode).GetSelectedSlopeVertexGroups(); + + addslopefloor.Enabled = svgs.Count == 1; + addslopeceiling.Enabled = svgs.Count == 1; + } + + private void addsectorscontextmenu_Closing(object sender, ToolStripDropDownClosingEventArgs e) + { + if( e.CloseReason != ToolStripDropDownCloseReason.ItemClicked && + e.CloseReason != ToolStripDropDownCloseReason.Keyboard && + e.CloseReason != ToolStripDropDownCloseReason.AppFocusChange) + ((SlopeMode)General.Editing.Mode).ContextMenuClosing = true; + } + + private void relocatecontrolsectors_Click(object sender, EventArgs e) + { + General.Interface.InvokeTaggedAction(sender, e); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/MenusForm.resx b/Source/Plugins/3DFloorMode/Windows/MenusForm.resx new file mode 100644 index 00000000..23345ded --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/MenusForm.resx @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== + + + + 122, 17 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.Designer.cs b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.Designer.cs new file mode 100644 index 00000000..5eb4d878 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.Designer.cs @@ -0,0 +1,104 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class SlopeDataSectorDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.useselectedsector = new System.Windows.Forms.Button(); + this.createnewsector = new System.Windows.Forms.Button(); + this.cancel = new System.Windows.Forms.Button(); + this.webBrowser1 = new System.Windows.Forms.WebBrowser(); + this.SuspendLayout(); + // + // useselectedsector + // + this.useselectedsector.Location = new System.Drawing.Point(147, 238); + this.useselectedsector.Name = "useselectedsector"; + this.useselectedsector.Size = new System.Drawing.Size(129, 23); + this.useselectedsector.TabIndex = 2; + this.useselectedsector.Text = "Use selected sector"; + this.useselectedsector.UseVisualStyleBackColor = true; + this.useselectedsector.Click += new System.EventHandler(this.button1_Click); + // + // createnewsector + // + this.createnewsector.Location = new System.Drawing.Point(12, 238); + this.createnewsector.Name = "createnewsector"; + this.createnewsector.Size = new System.Drawing.Size(129, 23); + this.createnewsector.TabIndex = 1; + this.createnewsector.Text = "Create sector in CSA"; + this.createnewsector.UseVisualStyleBackColor = true; + this.createnewsector.Click += new System.EventHandler(this.createnewsector_Click); + // + // cancel + // + this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancel.Location = new System.Drawing.Point(282, 238); + this.cancel.Name = "cancel"; + this.cancel.Size = new System.Drawing.Size(129, 23); + this.cancel.TabIndex = 3; + this.cancel.Text = "Cancel"; + this.cancel.UseVisualStyleBackColor = true; + // + // webBrowser1 + // + this.webBrowser1.Location = new System.Drawing.Point(12, 12); + this.webBrowser1.MinimumSize = new System.Drawing.Size(20, 20); + this.webBrowser1.Name = "webBrowser1"; + this.webBrowser1.ScrollBarsEnabled = false; + this.webBrowser1.Size = new System.Drawing.Size(399, 220); + this.webBrowser1.TabIndex = 4; + // + // SlopeDataSectorDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancel; + this.ClientSize = new System.Drawing.Size(423, 273); + this.Controls.Add(this.webBrowser1); + this.Controls.Add(this.cancel); + this.Controls.Add(this.createnewsector); + this.Controls.Add(this.useselectedsector); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SlopeDataSectorDialog"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Slope data sector"; + this.Load += new System.EventHandler(this.SlopeDataSectorDialog_Load); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button useselectedsector; + private System.Windows.Forms.Button createnewsector; + private System.Windows.Forms.Button cancel; + private System.Windows.Forms.WebBrowser webBrowser1; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.cs b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.cs new file mode 100644 index 00000000..3f343358 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Windows; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class SlopeDataSectorDialog : Form + { + public SlopeDataSectorDialog() + { + InitializeComponent(); + } + + private void button1_Click(object sender, EventArgs e) + { + if (General.Map.Map.SelectedSectorsCount == 0) + MessageBox.Show("No sectors selected. Please select exactly one sector", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + else if (General.Map.Map.SelectedSectorsCount > 1) + MessageBox.Show(General.Map.Map.SelectedSectorsCount.ToString() + " sectors selected. Please select exactly one sector", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + else + { + General.Map.Map.ClearAllMarks(false); + General.Map.Map.GetSelectedSectors(true).First().Marked = true; + + this.DialogResult = DialogResult.OK; + this.Close(); + } + } + + private void SlopeDataSectorDialog_Load(object sender, EventArgs e) + { + webBrowser1.DocumentText = string.Format(System.Globalization.CultureInfo.GetCultureInfo("en-US"), @" + + +The map does not contain a slope data sector. This sector is required by the slope mode to store data for the slope vertex groups. + +You have two options: +
    +
  • Use selected sector: uses the currently selected sector to store the slope data. Make sure that this sector is only +used for this purpose! Do not edit or delete it!
  • +
  • Create sector in CSA: automatically creates a new sector in the control sector area. Do not edit or delete it!
  • +
+ +Creating the sector in the CSA is the recommended method to use.", this.BackColor.R, this.BackColor.G, this.BackColor.B, this.Font.Name); + } + + private void createnewsector_Click(object sender, EventArgs e) + { + List drawnvertices = new List(); + + try + { + drawnvertices = BuilderPlug.Me.ControlSectorArea.GetNewControlSectorVertices(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + General.Map.Map.ClearAllMarks(false); + + // DrawLines automatically marks the new sector, so we don't have to do it manually + if (Tools.DrawLines(drawnvertices) == false) + { + MessageBox.Show("Could not draw new sector", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + // Update textures + General.Map.Data.UpdateUsedTextures(); + + // Update caches + General.Map.Map.Update(); + General.Interface.RedrawDisplay(); + General.Map.IsChanged = true; + + this.DialogResult = DialogResult.OK; + this.Close(); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.resx b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.resx new file mode 100644 index 00000000..19dc0dd8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs new file mode 100644 index 00000000..4979ca50 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs @@ -0,0 +1,342 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class SlopeVertexEditForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.apply = new System.Windows.Forms.Button(); + this.cancel = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.positionz = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.positiony = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.positionx = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.checkedListBoxSectors = new System.Windows.Forms.CheckedListBox(); + this.reposition = new System.Windows.Forms.CheckBox(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.removeselectedsectorsceiling = new System.Windows.Forms.CheckBox(); + this.addselectedsectorsceiling = new System.Windows.Forms.CheckBox(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.removeselectedsectorsfloor = new System.Windows.Forms.CheckBox(); + this.addselectedsectorsfloor = new System.Windows.Forms.CheckBox(); + this.spline = new System.Windows.Forms.CheckBox(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.SuspendLayout(); + // + // apply + // + this.apply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.apply.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.apply.Location = new System.Drawing.Point(260, 174); + this.apply.Name = "apply"; + this.apply.Size = new System.Drawing.Size(112, 25); + this.apply.TabIndex = 0; + this.apply.Text = "OK"; + this.apply.UseVisualStyleBackColor = true; + this.apply.Click += new System.EventHandler(this.apply_Click); + // + // cancel + // + this.cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancel.Location = new System.Drawing.Point(380, 174); + this.cancel.Name = "cancel"; + this.cancel.Size = new System.Drawing.Size(112, 25); + this.cancel.TabIndex = 1; + this.cancel.Text = "Cancel"; + this.cancel.UseVisualStyleBackColor = true; + this.cancel.Click += new System.EventHandler(this.cancel_Click); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Controls.Add(this.positionz); + this.groupBox1.Controls.Add(this.positiony); + this.groupBox1.Controls.Add(this.positionx); + this.groupBox1.Location = new System.Drawing.Point(18, 13); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(149, 114); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Position"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(6, 87); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(17, 14); + this.label3.TabIndex = 15; + this.label3.Text = "Z:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.Location = new System.Drawing.Point(6, 57); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(17, 14); + this.label2.TabIndex = 14; + this.label2.Text = "Y:"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(6, 25); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(17, 14); + this.label1.TabIndex = 13; + this.label1.Text = "X:"; + // + // positionz + // + this.positionz.AllowDecimal = true; + this.positionz.AllowExpressions = false; + this.positionz.AllowNegative = true; + this.positionz.AllowRelative = true; + this.positionz.BackColor = System.Drawing.Color.Transparent; + this.positionz.ButtonStep = 8; + this.positionz.ButtonStepBig = 16F; + this.positionz.ButtonStepFloat = 8F; + this.positionz.ButtonStepSmall = 1F; + this.positionz.ButtonStepsUseModifierKeys = true; + this.positionz.ButtonStepsWrapAround = false; + this.positionz.Location = new System.Drawing.Point(29, 82); + this.positionz.Name = "positionz"; + this.positionz.Size = new System.Drawing.Size(115, 24); + this.positionz.StepValues = null; + this.positionz.TabIndex = 0; + // + // positiony + // + this.positiony.AllowDecimal = true; + this.positiony.AllowExpressions = false; + this.positiony.AllowNegative = true; + this.positiony.AllowRelative = true; + this.positiony.BackColor = System.Drawing.Color.Transparent; + this.positiony.ButtonStep = 8; + this.positiony.ButtonStepBig = 16F; + this.positiony.ButtonStepFloat = 8F; + this.positiony.ButtonStepSmall = 1F; + this.positiony.ButtonStepsUseModifierKeys = true; + this.positiony.ButtonStepsWrapAround = false; + this.positiony.Location = new System.Drawing.Point(29, 52); + this.positiony.Name = "positiony"; + this.positiony.Size = new System.Drawing.Size(115, 24); + this.positiony.StepValues = null; + this.positiony.TabIndex = 3; + // + // positionx + // + this.positionx.AllowDecimal = true; + this.positionx.AllowExpressions = false; + this.positionx.AllowNegative = true; + this.positionx.AllowRelative = true; + this.positionx.BackColor = System.Drawing.Color.Transparent; + this.positionx.ButtonStep = 8; + this.positionx.ButtonStepBig = 16F; + this.positionx.ButtonStepFloat = 8F; + this.positionx.ButtonStepSmall = 1F; + this.positionx.ButtonStepsUseModifierKeys = true; + this.positionx.ButtonStepsWrapAround = false; + this.positionx.Location = new System.Drawing.Point(29, 20); + this.positionx.Name = "positionx"; + this.positionx.Size = new System.Drawing.Size(115, 24); + this.positionx.StepValues = null; + this.positionx.TabIndex = 2; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.checkedListBoxSectors); + this.groupBox2.Location = new System.Drawing.Point(174, 13); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(113, 149); + this.groupBox2.TabIndex = 2; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Sectors to remove"; + // + // checkedListBoxSectors + // + this.checkedListBoxSectors.CheckOnClick = true; + this.checkedListBoxSectors.FormattingEnabled = true; + this.checkedListBoxSectors.Location = new System.Drawing.Point(6, 19); + this.checkedListBoxSectors.Name = "checkedListBoxSectors"; + this.checkedListBoxSectors.Size = new System.Drawing.Size(100, 124); + this.checkedListBoxSectors.TabIndex = 1; + // + // reposition + // + this.reposition.AutoSize = true; + this.reposition.Location = new System.Drawing.Point(18, 178); + this.reposition.Name = "reposition"; + this.reposition.Size = new System.Drawing.Size(187, 18); + this.reposition.TabIndex = 5; + this.reposition.Text = "Reposition after dragging sectors"; + this.reposition.UseVisualStyleBackColor = true; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.removeselectedsectorsceiling); + this.groupBox3.Controls.Add(this.addselectedsectorsceiling); + this.groupBox3.Location = new System.Drawing.Point(297, 13); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(195, 71); + this.groupBox3.TabIndex = 8; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Ceiling"; + // + // removeselectedsectorsceiling + // + this.removeselectedsectorsceiling.AutoSize = true; + this.removeselectedsectorsceiling.Location = new System.Drawing.Point(6, 43); + this.removeselectedsectorsceiling.Name = "removeselectedsectorsceiling"; + this.removeselectedsectorsceiling.Size = new System.Drawing.Size(174, 18); + this.removeselectedsectorsceiling.TabIndex = 6; + this.removeselectedsectorsceiling.Text = "Remove from selected sectors"; + this.removeselectedsectorsceiling.UseVisualStyleBackColor = true; + this.removeselectedsectorsceiling.CheckedChanged += new System.EventHandler(this.removeselectedsectorsceiling_CheckedChanged); + // + // addselectedsectorsceiling + // + this.addselectedsectorsceiling.AutoSize = true; + this.addselectedsectorsceiling.Location = new System.Drawing.Point(6, 19); + this.addselectedsectorsceiling.Name = "addselectedsectorsceiling"; + this.addselectedsectorsceiling.Size = new System.Drawing.Size(150, 18); + this.addselectedsectorsceiling.TabIndex = 5; + this.addselectedsectorsceiling.Text = "Apply to selected sectors"; + this.addselectedsectorsceiling.UseVisualStyleBackColor = true; + this.addselectedsectorsceiling.CheckedChanged += new System.EventHandler(this.addselectedsectorsceiling_CheckedChanged); + // + // groupBox4 + // + this.groupBox4.Controls.Add(this.removeselectedsectorsfloor); + this.groupBox4.Controls.Add(this.addselectedsectorsfloor); + this.groupBox4.Location = new System.Drawing.Point(297, 90); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(195, 72); + this.groupBox4.TabIndex = 9; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "Floor"; + // + // removeselectedsectorsfloor + // + this.removeselectedsectorsfloor.AutoSize = true; + this.removeselectedsectorsfloor.Location = new System.Drawing.Point(6, 43); + this.removeselectedsectorsfloor.Name = "removeselectedsectorsfloor"; + this.removeselectedsectorsfloor.Size = new System.Drawing.Size(174, 18); + this.removeselectedsectorsfloor.TabIndex = 9; + this.removeselectedsectorsfloor.Text = "Remove from selected sectors"; + this.removeselectedsectorsfloor.UseVisualStyleBackColor = true; + this.removeselectedsectorsfloor.CheckedChanged += new System.EventHandler(this.removeselectedsectorsfloor_CheckedChanged); + // + // addselectedsectorsfloor + // + this.addselectedsectorsfloor.AutoSize = true; + this.addselectedsectorsfloor.Location = new System.Drawing.Point(6, 19); + this.addselectedsectorsfloor.Name = "addselectedsectorsfloor"; + this.addselectedsectorsfloor.Size = new System.Drawing.Size(150, 18); + this.addselectedsectorsfloor.TabIndex = 8; + this.addselectedsectorsfloor.Text = "Apply to selected sectors"; + this.addselectedsectorsfloor.UseVisualStyleBackColor = true; + this.addselectedsectorsfloor.CheckedChanged += new System.EventHandler(this.addselectedsectorsfloor_CheckedChanged); + // + // spline + // + this.spline.AutoSize = true; + this.spline.Location = new System.Drawing.Point(18, 154); + this.spline.Name = "spline"; + this.spline.Size = new System.Drawing.Size(55, 18); + this.spline.TabIndex = 10; + this.spline.Text = "Spline"; + this.spline.UseVisualStyleBackColor = true; + // + // SlopeVertexEditForm + // + this.AcceptButton = this.apply; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 14F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancel; + this.ClientSize = new System.Drawing.Size(504, 211); + this.Controls.Add(this.spline); + this.Controls.Add(this.groupBox4); + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.reposition); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.cancel); + this.Controls.Add(this.apply); + this.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Name = "SlopeVertexEditForm"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Edit Slope Vertex"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button apply; + private System.Windows.Forms.Button cancel; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + public CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox positionz; + public CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox positiony; + public CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox positionx; + private System.Windows.Forms.GroupBox groupBox2; + public System.Windows.Forms.CheckedListBox checkedListBoxSectors; + private System.Windows.Forms.CheckBox reposition; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.CheckBox removeselectedsectorsceiling; + private System.Windows.Forms.CheckBox addselectedsectorsceiling; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.CheckBox removeselectedsectorsfloor; + private System.Windows.Forms.CheckBox addselectedsectorsfloor; + private System.Windows.Forms.CheckBox spline; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.cs b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.cs new file mode 100644 index 00000000..7cfb3984 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.cs @@ -0,0 +1,222 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class SlopeVertexEditForm : Form + { + private List vertices; + private List sectors; + private string undodescription; + private bool canaddsectors; + private bool canremovesectors; + + public SlopeVertexEditForm() + { + InitializeComponent(); + } + + public void Setup(List vertices) + { + this.vertices = vertices; + + SlopeVertex fv = vertices[0]; + SlopeVertexGroup fsvg = BuilderPlug.Me.GetSlopeVertexGroup(fv); + + sectors = new List(); + + undodescription = "Edit slope vertex"; + + if (vertices.Count > 1) + undodescription = "Edit " + vertices.Count + " slope vertices"; + + positionx.Text = fv.Pos.x.ToString(); + positiony.Text = fv.Pos.y.ToString(); + positionz.Text = fv.Z.ToString(); + + foreach (Sector s in fsvg.Sectors) + if (!sectors.Contains(s)) + sectors.Add(s); + + reposition.Checked = fsvg.Reposition; + spline.Checked = fsvg.Spline; + + canaddsectors = true; + canremovesectors = true; + + if (vertices.Count > 1) + { + List listsvgs = new List(); + + this.Text = "Edit slope vertices (" + vertices.Count.ToString() + ")"; + + foreach (SlopeVertex sv in vertices) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(sv); + + if (!listsvgs.Contains(svg)) + listsvgs.Add(svg); + + if (sv.Pos.x.ToString() != positionx.Text) + positionx.Text = ""; + + if (sv.Pos.y.ToString() != positiony.Text) + positiony.Text = ""; + + if (sv.Z.ToString() != positionz.Text) + positionz.Text = ""; + + if (svg.Reposition != reposition.Checked) + reposition.CheckState = CheckState.Indeterminate; + + if (svg.Spline) + spline.Enabled = true; + + if (svg.Spline != spline.Checked) + spline.CheckState = CheckState.Indeterminate; + + foreach (Sector s in svg.Sectors) + if (!sectors.Contains(s)) + sectors.Add(s); + } + + if (listsvgs.Count > 2) + { + canaddsectors = false; + canremovesectors = false; + } + } + + foreach (Sector s in sectors.OrderBy(x => x.Index)) + { + checkedListBoxSectors.Items.Add(s); + } + + if (General.Map.Map.SelectedSectorsCount == 0) + { + addselectedsectorsceiling.Enabled = false; + removeselectedsectorsceiling.Enabled = false; + addselectedsectorsfloor.Enabled = false; + removeselectedsectorsfloor.Enabled = false; + } + else + { + addselectedsectorsceiling.Enabled = canaddsectors; + removeselectedsectorsceiling.Enabled = canremovesectors; + addselectedsectorsfloor.Enabled = canaddsectors; + removeselectedsectorsfloor.Enabled = canremovesectors; + } + } + + private void apply_Click(object sender, EventArgs e) + { + List groups = new List(); + + // undodescription was set in the Setup method + General.Map.UndoRedo.CreateUndo(undodescription); + + foreach (SlopeVertex sv in vertices) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(sv); + float x = positionx.GetResultFloat(sv.Pos.x); + float y = positiony.GetResultFloat(sv.Pos.y); + + sv.Pos = new Vector2D(x, y); + + sv.Z = positionz.GetResultFloat(sv.Z); + + if (!groups.Contains(svg)) + groups.Add(svg); + } + + foreach (SlopeVertexGroup svg in groups) + { + if (reposition.CheckState != CheckState.Indeterminate) + svg.Reposition = reposition.Checked; + + if (spline.CheckState != CheckState.Indeterminate && svg.Vertices.Count == 3) + svg.Spline = spline.Checked; + + // Ceiling + if (addselectedsectorsceiling.Checked) + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + svg.AddSector(s, PlaneType.Ceiling); + + if (removeselectedsectorsceiling.Checked) + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + if (svg.Sectors.Contains(s)) + svg.RemoveSector(s, PlaneType.Ceiling); + + // Floor + if (addselectedsectorsfloor.Checked) + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + svg.AddSector(s, PlaneType.Floor); + + if (removeselectedsectorsfloor.Checked) + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + if (svg.Sectors.Contains(s)) + svg.RemoveSector(s, PlaneType.Floor); + + foreach (Sector s in checkedListBoxSectors.CheckedItems) + { + if (svg.Sectors.Contains(s)) + { + svg.RemoveSector(s, PlaneType.Floor); + svg.RemoveSector(s, PlaneType.Ceiling); + } + } + + svg.ApplyToSectors(); + } + + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + + this.DialogResult = DialogResult.OK; + } + + private void cancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + } + + private void addselectedsectorsceiling_CheckedChanged(object sender, EventArgs e) + { + // Adding and removing selected sectors at the same time doesn't make sense, + // so make sure only one of the checkboxes is checked at most + if (addselectedsectorsceiling.Checked) + removeselectedsectorsceiling.Checked = false; + } + + private void removeselectedsectorsceiling_CheckedChanged(object sender, EventArgs e) + { + // Adding and removing selected sectors at the same time doesn't make sense, + // so make sure only one of the checkboxes is checked at most + if (removeselectedsectorsceiling.Checked) + addselectedsectorsceiling.Checked = false; + } + + private void addselectedsectorsfloor_CheckedChanged(object sender, EventArgs e) + { + // Adding and removing selected sectors at the same time doesn't make sense, + // so make sure only one of the checkboxes is checked at most + if (addselectedsectorsfloor.Checked) + removeselectedsectorsfloor.Checked = false; + } + + private void removeselectedsectorsfloor_CheckedChanged(object sender, EventArgs e) + { + // Adding and removing selected sectors at the same time doesn't make sense, + // so make sure only one of the checkboxes is checked at most + if (removeselectedsectorsfloor.Checked) + addselectedsectorsfloor.Checked = false; + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.resx b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.resx new file mode 100644 index 00000000..d58980a3 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.Designer.cs b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.Designer.cs new file mode 100644 index 00000000..1e229f00 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.Designer.cs @@ -0,0 +1,181 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ThreeDFloorEditorWindow + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.threeDFloorPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.addThreeDFloorButton = new System.Windows.Forms.Button(); + this.sharedThreeDFloorsCheckBox = new System.Windows.Forms.CheckBox(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.no3dfloorspanel = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.add3dfloorbutton2 = new System.Windows.Forms.Button(); + this.no3dfloorspanel.SuspendLayout(); + this.SuspendLayout(); + // + // threeDFloorPanel + // + this.threeDFloorPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.threeDFloorPanel.AutoScroll = true; + this.threeDFloorPanel.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.threeDFloorPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.threeDFloorPanel.Location = new System.Drawing.Point(12, 6); + this.threeDFloorPanel.Name = "threeDFloorPanel"; + this.threeDFloorPanel.Size = new System.Drawing.Size(760, 500); + this.threeDFloorPanel.TabIndex = 0; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.Location = new System.Drawing.Point(616, 513); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 3; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(697, 513); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 4; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // addThreeDFloorButton + // + this.addThreeDFloorButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.addThreeDFloorButton.Location = new System.Drawing.Point(12, 513); + this.addThreeDFloorButton.Name = "addThreeDFloorButton"; + this.addThreeDFloorButton.Size = new System.Drawing.Size(75, 23); + this.addThreeDFloorButton.TabIndex = 1; + this.addThreeDFloorButton.Text = "Add 3D floor"; + this.addThreeDFloorButton.UseVisualStyleBackColor = true; + this.addThreeDFloorButton.Click += new System.EventHandler(this.addThreeDFloorButton_Click); + // + // sharedThreeDFloorsCheckBox + // + this.sharedThreeDFloorsCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.sharedThreeDFloorsCheckBox.AutoSize = true; + this.sharedThreeDFloorsCheckBox.Location = new System.Drawing.Point(93, 517); + this.sharedThreeDFloorsCheckBox.Name = "sharedThreeDFloorsCheckBox"; + this.sharedThreeDFloorsCheckBox.Size = new System.Drawing.Size(155, 17); + this.sharedThreeDFloorsCheckBox.TabIndex = 2; + this.sharedThreeDFloorsCheckBox.Text = "Show shared 3D floors only"; + this.toolTip1.SetToolTip(this.sharedThreeDFloorsCheckBox, "If checked only shows the 3D floors that\r\nare shared among all selected sectors"); + this.sharedThreeDFloorsCheckBox.UseVisualStyleBackColor = true; + this.sharedThreeDFloorsCheckBox.CheckedChanged += new System.EventHandler(this.sharedThreeDFloorsCheckBox_CheckedChanged); + // + // no3dfloorspanel + // + this.no3dfloorspanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.no3dfloorspanel.Controls.Add(this.add3dfloorbutton2); + this.no3dfloorspanel.Controls.Add(this.label1); + this.no3dfloorspanel.Location = new System.Drawing.Point(12, 6); + this.no3dfloorspanel.Name = "no3dfloorspanel"; + this.no3dfloorspanel.Size = new System.Drawing.Size(760, 500); + this.no3dfloorspanel.TabIndex = 0; + // + // label1 + // + this.label1.Anchor = System.Windows.Forms.AnchorStyles.None; + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(279, 212); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(227, 25); + this.label1.TabIndex = 0; + this.label1.Text = "There are no 3D floors"; + // + // add3dfloorbutton2 + // + this.add3dfloorbutton2.Anchor = System.Windows.Forms.AnchorStyles.None; + this.add3dfloorbutton2.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.add3dfloorbutton2.Location = new System.Drawing.Point(320, 254); + this.add3dfloorbutton2.Name = "add3dfloorbutton2"; + this.add3dfloorbutton2.Size = new System.Drawing.Size(145, 33); + this.add3dfloorbutton2.TabIndex = 1; + this.add3dfloorbutton2.Text = "Add 3D floor"; + this.add3dfloorbutton2.UseVisualStyleBackColor = true; + this.add3dfloorbutton2.Click += new System.EventHandler(this.addThreeDFloorButton_Click); + // + // ThreeDFloorEditorWindow + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(784, 548); + this.Controls.Add(this.no3dfloorspanel); + this.Controls.Add(this.sharedThreeDFloorsCheckBox); + this.Controls.Add(this.addThreeDFloorButton); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okButton); + this.Controls.Add(this.threeDFloorPanel); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(800, 2000); + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(800, 200); + this.Name = "ThreeDFloorEditorWindow"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "3D floors"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ThreeDFloorEditorWindow_FormClosed); + this.Load += new System.EventHandler(this.ThreeDFloorEditorWindow_Load); + this.no3dfloorspanel.ResumeLayout(false); + this.no3dfloorspanel.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.FlowLayoutPanel threeDFloorPanel; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Button addThreeDFloorButton; + private System.Windows.Forms.CheckBox sharedThreeDFloorsCheckBox; + private System.Windows.Forms.ToolTip toolTip1; + private System.Windows.Forms.Panel no3dfloorspanel; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button add3dfloorbutton2; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.cs b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.cs new file mode 100644 index 00000000..3b0967ea --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Text.RegularExpressions; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ThreeDFloorEditorWindow : Form + { + List threedfloors; + List selectedsectors; + List controlpool; + + public List SelectedSectors { get { return selectedsectors; } } + + public List ThreeDFloors { get { return threedfloors; } set { threedfloors = value; } } + + public ThreeDFloorEditorWindow() + { + this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width/2, Screen.PrimaryScreen.WorkingArea.Height/2); + controlpool = new List(); + InitializeComponent(); + } + + private void ThreeDFloorEditorWindow_Load(object sender, EventArgs e) + { + selectedsectors = new List(General.Map.Map.GetSelectedSectors(true)); + sharedThreeDFloorsCheckBox.Checked = false; + FillThreeDFloorPanel(threedfloors); + } + + // Gets a control from the pool or creates a new one + private ThreeDFloorHelperControl GetThreeDFloorControl() + { + ThreeDFloorHelperControl ctrl = controlpool.FirstOrDefault(o => o.Used == false); + + if (ctrl == null) + { + ctrl = new ThreeDFloorHelperControl(); + ctrl.Used = true; + controlpool.Add(ctrl); + threeDFloorPanel.Controls.Add(ctrl); + } + else + { + ctrl.SetDefaults(); + ctrl.Used = true; + } + + return ctrl; + } + + private void okButton_Click(object sender, EventArgs e) + { + threedfloors = new List(); + + foreach (ThreeDFloorHelperControl ctrl in threeDFloorPanel.Controls.OfType()) + { + if (ctrl.Used) + { + ctrl.ApplyToThreeDFloor(); + threedfloors.Add(ctrl.ThreeDFloor); + } + } + + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void cancelButton_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + public void addThreeDFloorButton_Click(object sender, EventArgs e) + { + ThreeDFloorHelperControl ctrl = GetThreeDFloorControl(); + + ctrl.Show(); + + threeDFloorPanel.ScrollControlIntoView(ctrl); + + no3dfloorspanel.Hide(); + } + + public void DuplicateThreeDFloor(ThreeDFloorHelperControl ctrl) + { + ThreeDFloorHelperControl dup = GetThreeDFloorControl(); + + dup.Update(ctrl); + dup.Show(); + + threeDFloorPanel.ScrollControlIntoView(dup); + } + + public void SplitThreeDFloor(ThreeDFloorHelperControl ctrl) + { + var items = new List(); + var controls = new List(); + int numsplits = 0; + + for (int i = 0; i < ctrl.checkedListBoxSectors.Items.Count; i++) + { + if(ctrl.checkedListBoxSectors.GetItemCheckState(i) == CheckState.Checked) + items.Add(i); + } + + int useitem = items.Count - 1; + + /* + Case 1: all tagged sectors are also selected sectors. In this case we can reuse + the original control, so one less additional control is needed + Case 2: multiple tagged sectors are also selected sectors. In this case we can + reuse the original control, so one less additional control is needed + Case 3: only one tagged sector is also the selected sector. In this case we + have to add exactly one additional control + */ + + controls.Add(ctrl); + + if (items.Count == 1) + { + numsplits = 1; + } + else + { + numsplits = items.Count - 1; + } + + for (int i = 0; i < numsplits; i++) + { + var newctrl = GetThreeDFloorControl(); + + newctrl.Update(ctrl); + newctrl.Show(); + + controls.Add(newctrl); + } + + for (int i = controls.Count - 1; i >= 0 ; i--) + { + for (int j = 0; j < items.Count; j++) + { + controls[i].checkedListBoxSectors.SetItemChecked(j, false); + } + + if (useitem >= 0) + controls[i].checkedListBoxSectors.SetItemChecked(items[useitem], true); + + useitem--; + } + } + + public void DetachThreeDFloor(ThreeDFloorHelperControl ctrl) + { + ThreeDFloorHelperControl dup = GetThreeDFloorControl(); + + dup.Update(ctrl); + + for (int i = 0; i < ctrl.checkedListBoxSectors.Items.Count; i++) + { + if (ctrl.checkedListBoxSectors.GetItemCheckState(i) == CheckState.Checked) + ctrl.checkedListBoxSectors.SetItemChecked(i, false); + } + + dup.Show(); + + threeDFloorPanel.ScrollControlIntoView(dup); + } + + private void FillThreeDFloorPanel(List threedfloors) + { + if (threedfloors.Count > 0) + { + // Create a new controller instance for each linedef and set its properties + foreach (ThreeDFloor tdf in threedfloors.OrderByDescending(o => o.TopHeight).ToList()) + { + ThreeDFloorHelperControl ctrl = GetThreeDFloorControl(); + ctrl.Update(tdf); + ctrl.Show(); + } + + no3dfloorspanel.Hide(); + } + else + { + no3dfloorspanel.Show(); + } + + // Hide all unused pool controls + if (controlpool.Count - threedfloors.Count > 0) + { + foreach (ThreeDFloorHelperControl ctrl in controlpool.Skip(threedfloors.Count)) + { + ctrl.Used = false; + ctrl.Hide(); + } + } + } + + private void sharedThreeDFloorsCheckBox_CheckedChanged(object sender, EventArgs e) + { + ICollection selectedSectors = General.Map.Map.GetSelectedSectors(true); + + if (selectedSectors.Count > 1 && sharedThreeDFloorsCheckBox.Checked) + { + var hideControls = new List(); + + foreach (Sector s in selectedSectors) + { + foreach (ThreeDFloorHelperControl ctrl in threeDFloorPanel.Controls.OfType()) + { + // If the selected sector is not in the control's tagged sectors the control + // should be hidden + if (!ctrl.ThreeDFloor.TaggedSectors.Contains(s)) + hideControls.Add(ctrl); + } + } + + foreach (ThreeDFloorHelperControl ctrl in hideControls) + { + // Hide controls, unless they are new + if (ctrl.IsNew == false) + ctrl.Hide(); + } + } + else + { + foreach (ThreeDFloorHelperControl ctrl in threeDFloorPanel.Controls.OfType()) + if (ctrl.Used) + ctrl.Show(); + } + } + + private void ThreeDFloorEditorWindow_FormClosed(object sender, FormClosedEventArgs e) + { + // Get rid of dummy sectors and makes all controls available + foreach (ThreeDFloorHelperControl ctrl in threeDFloorPanel.Controls.OfType().ToList()) + { + if (ctrl.Sector != null) + ctrl.Sector.Dispose(); + + ctrl.Used = false; + } + + General.Map.Map.Update(); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.resx b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.resx new file mode 100644 index 00000000..84f73fcc --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/build_git_generic.cmd b/build_git_generic.cmd index 42e66159..bc17ed48 100755 --- a/build_git_generic.cmd +++ b/build_git_generic.cmd @@ -182,6 +182,15 @@ msbuild "Source\Plugins\TagRange\TagRange.csproj" /t:Rebuild /p:Configuration=Re IF %ERRORLEVEL% NEQ 0 GOTO ERRORFAIL IF NOT EXIST "Build\Plugins\TagRange.dll" GOTO FILEFAIL +ECHO. +ECHO Compiling 3D Floor Mode plugin... +ECHO. +IF EXIST "Build\Plugins\ThreeDFloorMode.dll" DEL /F /Q "Build\Plugins\ThreeDFloorMode.dll" > NUL +IF EXIST "Source\Plugins\3DFloorMode\obj" RD /S /Q "Source\Plugins\3DFloorMode\obj" +msbuild "Source\Plugins\3DFloorMode\ThreeDFloorMode.csproj" /t:Rebuild /p:Configuration=Release /p:Platform=%PLATFORM% /v:minimal +IF %ERRORLEVEL% NEQ 0 GOTO ERRORFAIL +IF NOT EXIST "Build\Plugins\ThreeDFloorMode.dll" GOTO FILEFAIL + ECHO. ECHO Compiling vpo_dll... ECHO. @@ -191,7 +200,6 @@ msbuild "Source\Plugins\vpo_dll\vpo_dll.vcxproj" /t:Rebuild /p:Configuration=Rel IF %ERRORLEVEL% NEQ 0 GOTO ERRORFAIL IF NOT EXIST "Source\Plugins\VisplaneExplorer\Resources\vpo.dll" GOTO FILEFAIL - ECHO. ECHO Compiling Visplane Explorer plugin... ECHO.