Drawable.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. //
  2. // Copyright (c) 2008-2013 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 "Camera.h"
  24. #include "Context.h"
  25. #include "DebugRenderer.h"
  26. #include "Log.h"
  27. #include "Material.h"
  28. #include "Octree.h"
  29. #include "Scene.h"
  30. #include "Sort.h"
  31. #include "Zone.h"
  32. #include "DebugNew.h"
  33. namespace Urho3D
  34. {
  35. const char* GEOMETRY_CATEGORY = "Geometry";
  36. SourceBatch::SourceBatch() :
  37. distance_(0.0f),
  38. geometry_(0),
  39. worldTransform_(&Matrix3x4::IDENTITY),
  40. shaderData_(0),
  41. shaderDataSize_(0),
  42. geometryType_(GEOM_STATIC),
  43. overrideView_(false)
  44. {
  45. }
  46. SourceBatch::~SourceBatch()
  47. {
  48. }
  49. Drawable::Drawable(Context* context, unsigned char drawableFlags) :
  50. Component(context),
  51. drawableFlags_(drawableFlags),
  52. worldBoundingBoxDirty_(true),
  53. castShadows_(false),
  54. occluder_(false),
  55. occludee_(true),
  56. updateQueued_(false),
  57. reinsertionQueued_(false),
  58. viewMask_(DEFAULT_VIEWMASK),
  59. lightMask_(DEFAULT_LIGHTMASK),
  60. shadowMask_(DEFAULT_SHADOWMASK),
  61. zoneMask_(DEFAULT_ZONEMASK),
  62. viewFrameNumber_(0),
  63. distance_(0.0f),
  64. lodDistance_(0.0f),
  65. drawDistance_(0.0f),
  66. shadowDistance_(0.0f),
  67. sortValue_(0.0f),
  68. minZ_(0.0f),
  69. maxZ_(0.0f),
  70. lodBias_(1.0f),
  71. basePassFlags_(0),
  72. maxLights_(0),
  73. octant_(0),
  74. firstLight_(0),
  75. viewFrame_(0),
  76. viewCamera_(0),
  77. zoneDirty_(false)
  78. {
  79. }
  80. Drawable::~Drawable()
  81. {
  82. RemoveFromOctree();
  83. }
  84. void Drawable::RegisterObject(Context* context)
  85. {
  86. ATTRIBUTE(Drawable, VAR_INT, "Max Lights", maxLights_, 0, AM_DEFAULT);
  87. ATTRIBUTE(Drawable, VAR_INT, "View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
  88. ATTRIBUTE(Drawable, VAR_INT, "Light Mask", lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
  89. ATTRIBUTE(Drawable, VAR_INT, "Shadow Mask", shadowMask_, DEFAULT_SHADOWMASK, AM_DEFAULT);
  90. ACCESSOR_ATTRIBUTE(Drawable, VAR_INT, "Zone Mask", GetZoneMask, SetZoneMask, unsigned, DEFAULT_ZONEMASK, AM_DEFAULT);
  91. }
  92. void Drawable::OnSetEnabled()
  93. {
  94. bool enabled = IsEnabledEffective();
  95. if (enabled && !octant_)
  96. AddToOctree();
  97. else if (!enabled && octant_)
  98. RemoveFromOctree();
  99. }
  100. void Drawable::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
  101. {
  102. float distance = query.ray_.HitDistance(GetWorldBoundingBox());
  103. if (distance < query.maxDistance_)
  104. {
  105. RayQueryResult result;
  106. result.drawable_ = this;
  107. result.node_ = GetNode();
  108. result.distance_ = distance;
  109. result.subObject_ = M_MAX_UNSIGNED;
  110. results.Push(result);
  111. }
  112. }
  113. void Drawable::UpdateBatches(const FrameInfo& frame)
  114. {
  115. const Matrix3x4& worldTransform = node_->GetWorldTransform();
  116. distance_ = frame.camera_->GetDistance(node_->GetWorldPosition());
  117. for (unsigned i = 0; i < batches_.Size(); ++i)
  118. {
  119. batches_[i].distance_ = distance_;
  120. batches_[i].worldTransform_ = &worldTransform;
  121. }
  122. float scale = GetWorldBoundingBox().Size().DotProduct(DOT_SCALE);
  123. float newLodDistance = frame.camera_->GetLodDistance(distance_, scale, lodBias_);
  124. if (newLodDistance != lodDistance_)
  125. lodDistance_ = newLodDistance;
  126. }
  127. Geometry* Drawable::GetLodGeometry(unsigned batchIndex, unsigned level)
  128. {
  129. // By default return the visible batch geometry
  130. if (batchIndex < batches_.Size())
  131. return batches_[batchIndex].geometry_;
  132. else
  133. return 0;
  134. }
  135. void Drawable::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  136. {
  137. if (debug && IsEnabledEffective())
  138. debug->AddBoundingBox(GetWorldBoundingBox(), Color::GREEN, depthTest);
  139. }
  140. void Drawable::SetDrawDistance(float distance)
  141. {
  142. drawDistance_ = distance;
  143. MarkNetworkUpdate();
  144. }
  145. void Drawable::SetShadowDistance(float distance)
  146. {
  147. shadowDistance_ = distance;
  148. MarkNetworkUpdate();
  149. }
  150. void Drawable::SetLodBias(float bias)
  151. {
  152. lodBias_ = Max(bias, M_EPSILON);
  153. MarkNetworkUpdate();
  154. }
  155. void Drawable::SetViewMask(unsigned mask)
  156. {
  157. viewMask_ = mask;
  158. MarkNetworkUpdate();
  159. }
  160. void Drawable::SetLightMask(unsigned mask)
  161. {
  162. lightMask_ = mask;
  163. MarkNetworkUpdate();
  164. }
  165. void Drawable::SetShadowMask(unsigned mask)
  166. {
  167. shadowMask_ = mask;
  168. MarkNetworkUpdate();
  169. }
  170. void Drawable::SetZoneMask(unsigned mask)
  171. {
  172. zoneMask_ = mask;
  173. // Mark dirty to reset cached zone
  174. OnMarkedDirty(node_);
  175. MarkNetworkUpdate();
  176. }
  177. void Drawable::SetMaxLights(unsigned num)
  178. {
  179. maxLights_ = num;
  180. MarkNetworkUpdate();
  181. }
  182. void Drawable::SetCastShadows(bool enable)
  183. {
  184. castShadows_ = enable;
  185. MarkNetworkUpdate();
  186. }
  187. void Drawable::SetOccluder(bool enable)
  188. {
  189. occluder_ = enable;
  190. MarkNetworkUpdate();
  191. }
  192. void Drawable::SetOccludee(bool enable)
  193. {
  194. if (enable != occludee_)
  195. {
  196. occludee_ = enable;
  197. // Reinsert to octree to make sure octant occlusion does not erroneously hide this drawable
  198. if (octant_ && !reinsertionQueued_)
  199. octant_->GetRoot()->QueueReinsertion(this);
  200. MarkNetworkUpdate();
  201. }
  202. }
  203. void Drawable::MarkForUpdate()
  204. {
  205. if (!updateQueued_ && octant_)
  206. octant_->GetRoot()->QueueUpdate(this);
  207. }
  208. const BoundingBox& Drawable::GetWorldBoundingBox()
  209. {
  210. if (worldBoundingBoxDirty_)
  211. {
  212. OnWorldBoundingBoxUpdate();
  213. worldBoundingBoxDirty_ = false;
  214. }
  215. return worldBoundingBox_;
  216. }
  217. void Drawable::SetZone(Zone* zone, bool temporary)
  218. {
  219. zone_ = zone;
  220. lastZone_ = zone;
  221. // If the zone assignment was temporary (inconclusive) set the dirty flag so that it will be re-evaluated on the next frame
  222. zoneDirty_ = temporary;
  223. }
  224. void Drawable::SetSortValue(float value)
  225. {
  226. sortValue_ = value;
  227. }
  228. void Drawable::SetMinMaxZ(float minZ, float maxZ)
  229. {
  230. minZ_ = minZ;
  231. maxZ_ = maxZ;
  232. }
  233. void Drawable::MarkInView(const FrameInfo& frame, bool mainView)
  234. {
  235. if (mainView)
  236. {
  237. viewFrameNumber_ = frame.frameNumber_;
  238. viewFrame_ = &frame;
  239. viewCamera_ = frame.camera_;
  240. }
  241. else
  242. {
  243. if (viewFrameNumber_ != frame.frameNumber_ || viewFrame_ != &frame)
  244. {
  245. viewFrameNumber_ = frame.frameNumber_;
  246. viewFrame_ = &frame;
  247. viewCamera_ = 0;
  248. }
  249. }
  250. }
  251. void Drawable::ClearLights()
  252. {
  253. basePassFlags_ = 0;
  254. firstLight_ = 0;
  255. lights_.Clear();
  256. vertexLights_.Clear();
  257. }
  258. void Drawable::AddLight(Light* light)
  259. {
  260. if (lights_.Empty())
  261. firstLight_ = light;
  262. lights_.Push(light);
  263. }
  264. void Drawable::AddVertexLight(Light* light)
  265. {
  266. vertexLights_.Push(light);
  267. }
  268. void Drawable::LimitLights()
  269. {
  270. // Maximum lights value 0 means unlimited
  271. if (!maxLights_ || lights_.Size() <= maxLights_)
  272. return;
  273. // If more lights than allowed, move to vertex lights and cut the list
  274. const BoundingBox& box = GetWorldBoundingBox();
  275. for (unsigned i = 0; i < lights_.Size(); ++i)
  276. lights_[i]->SetIntensitySortValue(box);
  277. Sort(lights_.Begin(), lights_.End(), CompareDrawables);
  278. vertexLights_.Insert(vertexLights_.End(), lights_.Begin() + maxLights_, lights_.End());
  279. lights_.Resize(maxLights_);
  280. }
  281. void Drawable::LimitVertexLights()
  282. {
  283. if (vertexLights_.Size() <= MAX_VERTEX_LIGHTS)
  284. return;
  285. const BoundingBox& box = GetWorldBoundingBox();
  286. for (unsigned i = vertexLights_.Size() - 1; i < vertexLights_.Size(); --i)
  287. vertexLights_[i]->SetIntensitySortValue(box);
  288. Sort(vertexLights_.Begin(), vertexLights_.End(), CompareDrawables);
  289. vertexLights_.Resize(MAX_VERTEX_LIGHTS);
  290. }
  291. Zone* Drawable::GetZone() const
  292. {
  293. return zone_;
  294. }
  295. Zone* Drawable::GetLastZone() const
  296. {
  297. return lastZone_;
  298. }
  299. void Drawable::OnNodeSet(Node* node)
  300. {
  301. if (node)
  302. {
  303. AddToOctree();
  304. node->AddListener(this);
  305. }
  306. else
  307. RemoveFromOctree();
  308. }
  309. void Drawable::OnMarkedDirty(Node* node)
  310. {
  311. worldBoundingBoxDirty_ = true;
  312. if (!reinsertionQueued_ && octant_)
  313. octant_->GetRoot()->QueueReinsertion(this);
  314. // Mark zone assignment dirty. Due to possibly being called from a worker thread, it is unsafe to manipulate the Zone weak
  315. // pointer here
  316. if (node == node_)
  317. zoneDirty_ = true;
  318. }
  319. void Drawable::AddToOctree()
  320. {
  321. // Do not add to octree when disabled
  322. if (!IsEnabledEffective())
  323. return;
  324. Scene* scene = GetScene();
  325. if (scene)
  326. {
  327. Octree* octree = scene->GetComponent<Octree>();
  328. if (octree)
  329. octree->InsertDrawable(this);
  330. else
  331. LOGERROR("No Octree component in scene, drawable will not render");
  332. }
  333. else
  334. {
  335. // We have a mechanism for adding detached nodes to an octree manually, so do not log this error
  336. //LOGERROR("Node is detached from scene, drawable will not render");
  337. }
  338. }
  339. void Drawable::RemoveFromOctree()
  340. {
  341. if (octant_)
  342. {
  343. Octree* octree = octant_->GetRoot();
  344. if (updateQueued_)
  345. octree->CancelUpdate(this);
  346. if (reinsertionQueued_)
  347. octree->CancelReinsertion(this);
  348. octant_->RemoveDrawable(this);
  349. }
  350. }
  351. }