SplinePath.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. //
  2. // Copyright (c) 2008-2014 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "Log.h"
  25. #include "Scene.h"
  26. #include "SplinePath.h"
  27. namespace Urho3D
  28. {
  29. extern const char* interpolationModeNames[];
  30. extern const char* LOGIC_CATEGORY;
  31. SplinePath::SplinePath(Context* context) :
  32. Component(context),
  33. spline_(BEZIER_CURVE),
  34. speed_(1.f),
  35. elapsedTime_(0.f),
  36. traveled_(0.f),
  37. length_(0.f),
  38. dirty_(false),
  39. controlledNode_(NULL),
  40. controlledIdAttr_(0)
  41. {
  42. UpdateNodeIds();
  43. }
  44. void SplinePath::RegisterObject(Context* context)
  45. {
  46. context->RegisterFactory<SplinePath>(LOGIC_CATEGORY);
  47. ENUM_ACCESSOR_ATTRIBUTE(SplinePath, "Interpolation Mode", GetInterpolationMode, SetInterpolationMode, InterpolationMode, interpolationModeNames, BEZIER_CURVE, AM_FILE);
  48. ATTRIBUTE(SplinePath, VAR_FLOAT, "Speed", speed_, 1.f, AM_FILE);
  49. ATTRIBUTE(SplinePath, VAR_FLOAT, "Traveled", traveled_, 0.f, AM_FILE | AM_NOEDIT);
  50. ATTRIBUTE(SplinePath, VAR_FLOAT, "Elapsed Time", elapsedTime_, 0.f, AM_FILE | AM_NOEDIT);
  51. ACCESSOR_ATTRIBUTE(SplinePath, VAR_INT, "Controlled", GetControlledIdAttr, SetControlledIdAttr, unsigned, 0, AM_FILE | AM_NODEID);
  52. REF_ACCESSOR_ATTRIBUTE(SplinePath, VAR_VARIANTVECTOR, "Control Points", GetControlPointIdsAttr, SetControlPointIdsAttr, VariantVector, Variant::emptyVariantVector, AM_FILE | AM_NODEIDVECTOR);
  53. }
  54. void SplinePath::ApplyAttributes()
  55. {
  56. if (!dirty_)
  57. return;
  58. // Remove all old instance nodes before searching for new. Can not call RemoveAllInstances() as that would modify
  59. // the ID list on its own
  60. for (unsigned i = 0; i < controlPoints_.Size(); ++i)
  61. {
  62. Node* node = controlPoints_[i];
  63. if (node)
  64. node->RemoveListener(this);
  65. }
  66. controlPoints_.Clear();
  67. spline_.Clear();
  68. Scene* scene = GetScene();
  69. if (scene)
  70. {
  71. // The first index stores the number of IDs redundantly. This is for editing
  72. for (unsigned i = 1; i < controlPointIdsAttr_.Size(); ++i)
  73. {
  74. Node* node = scene->GetNode(controlPointIdsAttr_[i].GetUInt());
  75. if (node)
  76. {
  77. WeakPtr<Node> controlPoint(node);
  78. node->AddListener(this);
  79. controlPoints_.Push(controlPoint);
  80. spline_.AddKnot(node->GetWorldPosition());
  81. }
  82. }
  83. Node* node = scene->GetNode(controlledIdAttr_);
  84. if (node)
  85. {
  86. WeakPtr<Node> controlled(node);
  87. controlledNode_ = controlled;
  88. }
  89. }
  90. CalculateLength();
  91. dirty_ = false;
  92. }
  93. void SplinePath::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  94. {
  95. if (debug && node_ && IsEnabledEffective())
  96. {
  97. if (spline_.GetKnots().Size() > 1)
  98. {
  99. Vector3 a = spline_.GetPoint(0.f).GetVector3();
  100. for (float f = 0.01f; f <= 1.0f; f = f + 0.01f)
  101. {
  102. Vector3 b = spline_.GetPoint(f).GetVector3();
  103. debug->AddLine(a, b, Color::GREEN);
  104. a = b;
  105. }
  106. }
  107. for (Vector<WeakPtr<Node> >::ConstIterator i = controlPoints_.Begin(); i != controlPoints_.End(); ++i)
  108. debug->AddNode(*i);
  109. if (controlledNode_)
  110. debug->AddNode(controlledNode_);
  111. }
  112. }
  113. void SplinePath::AddControlPoint(Node* point, unsigned index)
  114. {
  115. if (!point)
  116. return;
  117. WeakPtr<Node> controlPoint(point);
  118. point->AddListener(this);
  119. controlPoints_.Insert(index, controlPoint);
  120. spline_.AddKnot(point->GetWorldPosition(), index);
  121. UpdateNodeIds();
  122. CalculateLength();
  123. }
  124. void SplinePath::RemoveControlPoint(Node* point)
  125. {
  126. if (!point)
  127. return;
  128. WeakPtr<Node> controlPoint(point);
  129. point->RemoveListener(this);
  130. for (unsigned i = 0; i < controlPoints_.Size(); ++i)
  131. {
  132. if (controlPoints_[i] == controlPoint)
  133. {
  134. controlPoints_.Erase(i);
  135. spline_.RemoveKnot(i);
  136. break;
  137. }
  138. }
  139. UpdateNodeIds();
  140. CalculateLength();
  141. }
  142. void SplinePath::ClearControlPoints()
  143. {
  144. for (unsigned i = 0; i < controlPoints_.Size(); ++i)
  145. {
  146. Node* node = controlPoints_[i];
  147. if (node)
  148. node->RemoveListener(this);
  149. }
  150. controlPoints_.Clear();
  151. spline_.Clear();
  152. UpdateNodeIds();
  153. CalculateLength();
  154. }
  155. void SplinePath::SetControlledNode(Node* controlled)
  156. {
  157. if (controlled)
  158. controlledNode_ = WeakPtr<Node>(controlled);
  159. }
  160. void SplinePath::SetInterpolationMode(InterpolationMode interpolationMode)
  161. {
  162. spline_.SetInterpolationMode(interpolationMode);
  163. CalculateLength();
  164. }
  165. void SplinePath::SetPosition(float factor)
  166. {
  167. float t = factor;
  168. if (t < 0.f)
  169. t = 0.0f;
  170. else if (t > 1.0f)
  171. t = 1.0f;
  172. traveled_ = t;
  173. }
  174. Vector3 SplinePath::GetPoint(float factor) const
  175. {
  176. return spline_.GetPoint(factor).GetVector3();
  177. }
  178. void SplinePath::Move(float timeStep)
  179. {
  180. if (traveled_ >= 1.0f || length_ <= 0.0f || controlledNode_.Null())
  181. return;
  182. elapsedTime_ += timeStep;
  183. // Calculate where we should be on the spline based on length, speed and time. If that is less than the set traveled_ don't move till caught up.
  184. float distanceCovered = elapsedTime_ * speed_;
  185. traveled_ = distanceCovered / length_;
  186. controlledNode_->SetWorldPosition(GetPoint(traveled_));
  187. }
  188. void SplinePath::Reset()
  189. {
  190. traveled_ = 0.f;
  191. elapsedTime_ = 0.f;
  192. }
  193. void SplinePath::SetControlPointIdsAttr(const VariantVector& value)
  194. {
  195. // Just remember the node IDs. They need to go through the SceneResolver, and we actually find the nodes during
  196. // ApplyAttributes()
  197. if (value.Size())
  198. {
  199. controlPointIdsAttr_.Clear();
  200. unsigned index = 0;
  201. unsigned numInstances = value[index++].GetUInt();
  202. // Prevent crash on entering negative value in the editor
  203. if (numInstances > M_MAX_INT)
  204. numInstances = 0;
  205. controlPointIdsAttr_.Push(numInstances);
  206. while (numInstances--)
  207. {
  208. // If vector contains less IDs than should, fill the rest with zeros
  209. if (index < value.Size())
  210. controlPointIdsAttr_.Push(value[index++].GetUInt());
  211. else
  212. controlPointIdsAttr_.Push(0);
  213. }
  214. dirty_ = true;
  215. }
  216. else
  217. {
  218. controlPointIdsAttr_.Clear();
  219. controlPointIdsAttr_.Push(0);
  220. dirty_ = true;
  221. }
  222. }
  223. void SplinePath::SetControlledIdAttr(unsigned value)
  224. {
  225. if (value > 0 && value < M_MAX_UNSIGNED)
  226. controlledIdAttr_ = value;
  227. dirty_ = true;
  228. }
  229. void SplinePath::OnMarkedDirty(Node* point)
  230. {
  231. if (!point)
  232. return;
  233. WeakPtr<Node> controlPoint(point);
  234. for (unsigned i = 0; i < controlPoints_.Size(); ++i)
  235. {
  236. if (controlPoints_[i] == controlPoint)
  237. {
  238. spline_.SetKnot(point->GetWorldPosition(), i);
  239. break;
  240. }
  241. }
  242. CalculateLength();
  243. }
  244. void SplinePath::OnNodeSetEnabled(Node* point)
  245. {
  246. if (!point)
  247. return;
  248. WeakPtr<Node> controlPoint(point);
  249. for (unsigned i = 0; i < controlPoints_.Size(); ++i)
  250. {
  251. if (controlPoints_[i] == controlPoint)
  252. {
  253. if (point->IsEnabled())
  254. spline_.AddKnot(point->GetWorldPosition(), i);
  255. else
  256. spline_.RemoveKnot(i);
  257. break;
  258. }
  259. }
  260. CalculateLength();
  261. }
  262. void SplinePath::UpdateNodeIds()
  263. {
  264. unsigned numInstances = controlPoints_.Size();
  265. controlPointIdsAttr_.Clear();
  266. controlPointIdsAttr_.Push(numInstances);
  267. for (unsigned i = 0; i < numInstances; ++i)
  268. {
  269. Node* node = controlPoints_[i];
  270. controlPointIdsAttr_.Push(node ? node->GetID() : 0);
  271. }
  272. }
  273. void SplinePath::CalculateLength()
  274. {
  275. if (spline_.GetKnots().Size() <= 0)
  276. return;
  277. length_ = 0.f;
  278. Vector3 a = spline_.GetKnot(0).GetVector3();
  279. for (float f = 0.000f; f <= 1.000f; f += 0.001f)
  280. {
  281. Vector3 b = spline_.GetPoint(f).GetVector3();
  282. length_ += Abs((a - b).Length());
  283. a = b;
  284. }
  285. }
  286. }