TubeTool.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. FinalSun/FinalAlert 2 Mission Editor
  3. Copyright (C) 1999-2024 Electronic Arts, Inc.
  4. Authored by Matthias Wagner
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. */
  16. #include "StdAfx.h"
  17. #include "TubeTool.h"
  18. #include "MapData.h"
  19. #include "IsoView.h"
  20. #include "Structs.h"
  21. #include "inlines.h"
  22. #include <memory>
  23. #include <algorithm>
  24. std::unique_ptr<CTube> findTubeEndAt(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, const CMapData& map)
  25. {
  26. const auto& tubes = map.GetTubes();
  27. auto it = std::find_if(tubes.begin(), tubes.end(), [mapCoords3d](const auto& tube) { return tube->getEndCoords() == mapCoords3d; });
  28. if (it != tubes.end())
  29. return std::make_unique<CTube>(**it);
  30. // if not found, also try with z - 4 (e.g. behind cliffs)
  31. auto backMapCoords = map.ToMapCoords3d(projCoords, map.GetHeightAt(mapCoords3d) - 4);
  32. it = std::find_if(tubes.begin(), tubes.end(), [backMapCoords](const auto& tube) { return tube->getEndCoords() == backMapCoords; });
  33. if (it != tubes.end())
  34. return std::make_unique<CTube>(**it);
  35. return nullptr;
  36. }
  37. std::vector<std::uint16_t> findTubesAt(const ProjectedCoords& projCoords, const CMapData& map)
  38. {
  39. std::vector<std::uint16_t> foundTubes;
  40. for (auto& t : map.GetTubes())
  41. {
  42. auto coords = map.ToMapCoords3d(projCoords, map.GetHeightAt(t->getStartCoords()));
  43. if (t->touches(coords))
  44. foundTubes.push_back(t->getId());
  45. }
  46. return foundTubes;
  47. }
  48. AddTubeTool::AddTubeTool(CMapData& map, CIsoView& view, bool bidirectional): MapTool(map, view),
  49. m_bidirectional(bidirectional)
  50. {
  51. }
  52. void AddTubeTool::finish()
  53. {
  54. if (m_tube) {
  55. if (m_tube->isValid())
  56. {
  57. getMap().SetTube(m_tube.get());
  58. if (m_bidirectional)
  59. {
  60. auto t2 = m_tube->reverse();
  61. getMap().SetTube(&t2);
  62. }
  63. }
  64. getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  65. }
  66. m_mm_tube.reset();
  67. m_tube.reset();
  68. m_modified_tubes.clear();
  69. }
  70. bool AddTubeTool::onRButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags)
  71. {
  72. if (!m_modified_tubes.empty())
  73. {
  74. // reset modified tubes to original state
  75. for (auto& tube : m_modified_tubes)
  76. {
  77. getMap().SetTube(tube.get());
  78. }
  79. }
  80. bool ret = m_tube != nullptr;
  81. m_mm_tube.reset();
  82. m_tube.reset();
  83. m_modified_tubes.clear();
  84. getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  85. return ret; // if we were adding or modifying a tube, a right click should just cancel this current tube, not the whole tool
  86. }
  87. void AddTubeTool::onLButtonDblClick(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags)
  88. {
  89. }
  90. void AddTubeTool::onLButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags)
  91. {
  92. if (!m_tube) {
  93. // first check if there is already a tube at the given location and take ownership if existing
  94. auto tube = getTubeToModify(mapCoords3d, projCoords, flags);
  95. if (tube) {
  96. m_tube = std::move(tube);
  97. // also find reverse direction
  98. if (m_bidirectional)
  99. {
  100. const auto& tubes = getMap().GetTubes();
  101. auto reversed = m_tube->reverse();
  102. auto reverseIt = std::find_if(tubes.begin(), tubes.end(), [&reversed](const auto& tube) { return tube->isEqual(reversed, true); });
  103. if (reverseIt != tubes.end())
  104. {
  105. m_modified_tubes.push_back(std::make_unique<CTube>(**reverseIt));
  106. getMap().DeleteTube((*reverseIt)->getId());
  107. }
  108. }
  109. m_modified_tubes.push_back(std::make_unique<CTube>(*m_tube));
  110. getMap().DeleteTube(m_tube->getId());
  111. }
  112. if (!m_tube) {
  113. // create a new tube, first click
  114. m_tube = std::move(createNewTube(mapCoords3d));
  115. }
  116. }
  117. else
  118. {
  119. int z = getMap().GetHeightAt(m_tube->getStartCoords());
  120. auto mc = getMap().ToMapCoords3d(projCoords, z);
  121. if (m_tube->getEndCoords() == MapCoords(mc.x, mc.y))
  122. {
  123. finish();
  124. }
  125. else
  126. {
  127. m_tube->append(mc.x, mc.y, m_tube->GetTubeParts().empty() ? 2 : 0);
  128. }
  129. }
  130. getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  131. }
  132. std::unique_ptr<CTube> AddTubeTool::createNewTube(const MapCoords& mapCoords3d) const
  133. {
  134. return std::make_unique<CTube>(mapCoords3d.x, mapCoords3d.y, ETubeDirection::Undefined, mapCoords3d.x, mapCoords3d.y, std::vector<ETubeDirection>());
  135. }
  136. std::unique_ptr<CTube> AddTubeTool::getTubeToModify(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, MapToolMouseFlags flags) const
  137. {
  138. if ((flags & MapToolMouseFlags::SHIFT) == MapToolMouseFlags::SHIFT)
  139. return findTubeEndAt(mapCoords3d, projCoords, getMap());
  140. return nullptr;
  141. }
  142. void AddTubeTool::onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags)
  143. {
  144. if (m_tube) {
  145. m_mm_tube.reset(new CTube(*m_tube));
  146. int z = getMap().GetHeightAt(m_tube->getStartCoords());
  147. auto mc = getMap().ToMapCoords3d(projCoords, z);
  148. m_mm_tube->append(mc.x, mc.y, m_tube->GetTubeParts().empty() ? 2 : 0);
  149. getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  150. }
  151. else
  152. {
  153. auto tube = getTubeToModify(mapCoords3d, projCoords, flags);
  154. if (tube)
  155. {
  156. m_hover_tube = std::move(tube);
  157. getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  158. }
  159. else if (m_hover_tube)
  160. {
  161. m_hover_tube.reset();
  162. getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  163. }
  164. }
  165. }
  166. void AddTubeTool::render()
  167. {
  168. if (m_mm_tube)
  169. {
  170. // mouse-move tube
  171. getView().DrawTube(*m_mm_tube);
  172. }
  173. else if (m_tube) {
  174. getView().DrawTube(*m_tube);
  175. }
  176. else if (m_hover_tube)
  177. {
  178. COLORREF col = RGB(0, 255, 0);
  179. getView().DrawTube(*m_hover_tube, nullptr, &col);
  180. }
  181. }
  182. RemoveTubeTool::RemoveTubeTool(CMapData& map, CIsoView& view) : MapTool(map, view)
  183. {
  184. }
  185. void RemoveTubeTool::onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags)
  186. {
  187. auto& m = getMap();
  188. std::vector<std::uint16_t> tubes = findTubesAt(projCoords, getMap());
  189. if ((flags & MapToolMouseFlags::LBUTTON) == MapToolMouseFlags::LBUTTON)
  190. {
  191. for (auto& id : tubes)
  192. {
  193. m.DeleteTube(id);
  194. }
  195. }
  196. else
  197. {
  198. m_hover_tubes.reserve(tubes.size());
  199. std::transform(tubes.begin(), tubes.end(), std::back_inserter(m_hover_tubes), [this](std::uint16_t tubeId) { return std::make_unique<CTube>(*getMap().GetTube(tubeId)); });
  200. }
  201. getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  202. m_hover_tubes.clear();
  203. }
  204. void RemoveTubeTool::render()
  205. {
  206. for(auto& tube: m_hover_tubes)
  207. {
  208. COLORREF col = RGB(0, 255, 0);
  209. getView().DrawTube(*tube, nullptr, &col);
  210. }
  211. }
  212. ModifyTubeTool::ModifyTubeTool(CMapData& map, CIsoView& view, bool bidirectional): AddTubeTool(map, view, bidirectional)
  213. {
  214. }
  215. std::unique_ptr<CTube> ModifyTubeTool::getTubeToModify(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, MapToolMouseFlags flags) const
  216. {
  217. return findTubeEndAt(mapCoords3d, projCoords, getMap());
  218. }
  219. std::unique_ptr<CTube> ModifyTubeTool::createNewTube(const MapCoords& mapCoords3d) const
  220. {
  221. return nullptr;
  222. }