Light2D.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  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 "../Core/Context.h"
  24. #include "../Graphics/Graphics.h"
  25. #include "../Graphics/Viewport.h"
  26. #include "../Scene/Scene.h"
  27. #include "../Graphics/Camera.h"
  28. #include "../Graphics/Octree.h"
  29. #include "../Atomic2D/Light2D.h"
  30. #include "../Graphics/Renderer.h"
  31. #include "../Resource/XMLFile.h"
  32. #include "../Graphics/GraphicsEvents.h"
  33. #include "../Graphics/RenderPath.h"
  34. #include "../Graphics/Material.h"
  35. #include "../Graphics/Technique.h"
  36. #include "../Graphics/Zone.h"
  37. #include "../Atomic2D/RigidBody2D.h"
  38. #include "../Atomic2D/Renderer2D.h"
  39. #include "../IO/Log.h"
  40. #include "../Resource/ResourceCache.h"
  41. namespace Atomic
  42. {
  43. extern const char* ATOMIC2D_CATEGORY;
  44. Light2D::Light2D(Context* context) : Component(context),
  45. lightgroupID_(0),
  46. color_(Color::WHITE),
  47. castShadows_(false),
  48. softShadows_(false),
  49. softShadowLength_(2.5f),
  50. backtrace_(false),
  51. raysInitialized_(false)
  52. {
  53. SetNumRays(32);
  54. }
  55. Light2D::~Light2D()
  56. {
  57. }
  58. void Light2D::SetNumRays(int numRays)
  59. {
  60. raysInitialized_ = false;
  61. rays_.Resize(numRays);
  62. }
  63. void Light2D::OnSceneSet(Scene* scene)
  64. {
  65. if (scene && !context_->GetEditorContext())
  66. {
  67. PODVector<Light2DGroup*> lightgroups;
  68. scene->GetComponents<Light2DGroup>(lightgroups, true);
  69. lightgroup_ = 0;
  70. for (unsigned i = 0; i < lightgroups.Size(); i++)
  71. {
  72. Light2DGroup* lightgroup = lightgroups.At(i);
  73. if (lightgroup->GetLightGroupID() == lightgroupID_)
  74. {
  75. lightgroup_ = lightgroup;
  76. lightgroup_->AddLight2D(this);
  77. break;
  78. }
  79. }
  80. if (lightgroup_.Null())
  81. {
  82. lightgroup_ = node_->CreateComponent<Light2DGroup>();
  83. lightgroup_->SetTemporary(true);
  84. lightgroup_->AddLight2D(this);
  85. }
  86. }
  87. else
  88. {
  89. if (lightgroup_)
  90. {
  91. lightgroup_->RemoveLight2D(this);
  92. lightgroup_ = 0;
  93. }
  94. }
  95. }
  96. void Light2D::OnSetEnabled()
  97. {
  98. Component::OnSetEnabled();
  99. if (lightgroup_)
  100. lightgroup_->SetDirty();
  101. if (!enabled_)
  102. {
  103. vertices_.Clear();
  104. }
  105. }
  106. void Light2D::AddVertices(Vector<Vertex2D>& vertices)
  107. {
  108. vertices += vertices_;
  109. }
  110. void Light2D::RegisterObject(Context* context)
  111. {
  112. context->RegisterFactory<Light2D>(ATOMIC2D_CATEGORY);
  113. ATOMIC_COPY_BASE_ATTRIBUTES(Component);
  114. ATOMIC_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
  115. ATOMIC_ACCESSOR_ATTRIBUTE("LightGroup", GetLightGroupID, SetLightGroupID, int, 0, AM_DEFAULT);
  116. ATOMIC_ACCESSOR_ATTRIBUTE("Color", GetColor, SetColor, Color, Color::WHITE, AM_DEFAULT);
  117. ATOMIC_ACCESSOR_ATTRIBUTE("Cast Shadows", GetCastShadows, SetCastShadows, bool, false, AM_DEFAULT);
  118. ATOMIC_ACCESSOR_ATTRIBUTE("Num Rays", GetNumRays, SetNumRays, int, 32, AM_DEFAULT);
  119. ATOMIC_ACCESSOR_ATTRIBUTE("Soft Shadows", GetSoftShadows, SetSoftShadows, bool, false, AM_DEFAULT);
  120. ATOMIC_ACCESSOR_ATTRIBUTE("Soft Shadows Length", GetSoftShadowLength, SetSoftShadowLength, float, 2.5f, AM_DEFAULT);
  121. ATOMIC_ACCESSOR_ATTRIBUTE("Backtrace", GetBacktrace, SetBacktrace, bool, false, AM_DEFAULT);
  122. }
  123. void Light2D::CastRays()
  124. {
  125. if (!raysInitialized_ || context_->GetEditorContext())
  126. return;
  127. PhysicsWorld2D* physicsWorld = lightgroup_->GetPhysicsWorld();
  128. if (physicsWorld && castShadows_) {
  129. for (unsigned i = 0; i < rays_.Size(); i++) {
  130. Light2DRay& ray = rays_[i];
  131. Vector2 oend = ray.end_;
  132. float distance = (ray.end_ - ray.start_).Length();
  133. if (Abs(distance < .01f))
  134. distance = .01f;
  135. float bestDistance = 999999;
  136. PODVector<PhysicsRaycastResult2D> results;
  137. physicsWorld->Raycast(results, ray.start_, ray.end_);
  138. RigidBody2D* body = NULL;
  139. for (PODVector<PhysicsRaycastResult2D>::ConstIterator itr = results.Begin(); itr != results.End(); itr++)
  140. {
  141. const PhysicsRaycastResult2D& result = *itr;
  142. if (result.body_->GetCastShadows() && result.distance_ < distance && result.distance_ < bestDistance)
  143. {
  144. bestDistance = result.distance_;
  145. body = result.body_;
  146. ray.fraction_ = result.distance_ / distance;
  147. ray.end_.x_ = result.position_.x_;
  148. ray.end_.y_ = result.position_.y_;
  149. }
  150. }
  151. // backtracing can introduce artifacts, for now don't backtrace
  152. // on static hit... also, may need to clamp on a body size
  153. if (backtrace_ && body && body->GetBodyType() != BT_STATIC)
  154. {
  155. results.Clear();
  156. bestDistance = -999999;
  157. physicsWorld->Raycast(results, oend, ray.end_);
  158. for (PODVector<PhysicsRaycastResult2D>::ConstIterator itr = results.Begin(); itr != results.End(); itr++)
  159. {
  160. const PhysicsRaycastResult2D& result = *itr;
  161. if (result.distance_ > bestDistance && result.body_->GetBodyType() != BT_STATIC)
  162. {
  163. bestDistance = result.distance_;
  164. ray.fraction_ = (distance - result.distance_) / distance;
  165. ray.end_.x_ = result.position_.x_;
  166. ray.end_.y_ = result.position_.y_;
  167. }
  168. }
  169. }
  170. }
  171. }
  172. }
  173. DirectionalLight2D::DirectionalLight2D(Context* context) : Light2D(context),
  174. direction_(-45.0f)
  175. {
  176. lightType_ = LIGHT2D_DIRECTIONAL;
  177. }
  178. DirectionalLight2D::~DirectionalLight2D()
  179. {
  180. }
  181. void DirectionalLight2D::RegisterObject(Context* context)
  182. {
  183. context->RegisterFactory<DirectionalLight2D>(ATOMIC2D_CATEGORY);
  184. ATOMIC_COPY_BASE_ATTRIBUTES(Light2D);
  185. ATOMIC_ACCESSOR_ATTRIBUTE("Direction", GetDirection, SetDirection, float, -45.0f, AM_DEFAULT);
  186. }
  187. void DirectionalLight2D::UpdateVertices()
  188. {
  189. if (!lightgroup_ || !enabled_ || context_->GetEditorContext())
  190. {
  191. vertices_.Clear();
  192. return;
  193. }
  194. const BoundingBox& frustumBox = lightgroup_->GetFrustumBox();
  195. float cos = Cos(direction_);
  196. float sin = Sin(direction_);
  197. float width = frustumBox.Size().x_;
  198. float height = frustumBox.Size().y_;
  199. if (!width || !height)
  200. return;
  201. float sizeOfScreen = width > height ? width : height;
  202. float xAxelOffSet = sizeOfScreen * cos;
  203. float yAxelOffSet = sizeOfScreen * sin;
  204. // preventing length <0 assertion error on box2d.
  205. if ((xAxelOffSet * xAxelOffSet < 0.1f) && (yAxelOffSet * yAxelOffSet < 0.1f)) {
  206. xAxelOffSet = 1;
  207. yAxelOffSet = 1;
  208. }
  209. float widthOffSet = sizeOfScreen * -sin;
  210. float heightOffSet = sizeOfScreen * cos;
  211. float x = (frustumBox.min_.x_ + frustumBox.max_.x_) * 0.5f - widthOffSet;
  212. float y = (frustumBox.min_.y_ + frustumBox.max_.y_) * 0.5f - heightOffSet;
  213. unsigned rayNum = rays_.Size();
  214. float portionX = 2.0f * widthOffSet / (rayNum - 1);
  215. x = (floorf(x / (portionX * 2))) * portionX * 2;
  216. float portionY = 2.0f * heightOffSet / (rayNum - 1);
  217. y = (ceilf(y / (portionY * 2))) * portionY * 2;
  218. for (unsigned i = 0; i < rayNum; i++)
  219. {
  220. Light2DRay& ray = rays_[i];
  221. float steppedX = float(i) * portionX + x;
  222. float steppedY = float(i) * portionY + y;
  223. ray.start_.x_ = steppedX - xAxelOffSet;
  224. ray.start_.y_ = steppedY - yAxelOffSet;
  225. ray.end_.x_ = steppedX + xAxelOffSet;
  226. ray.end_.y_ = steppedY + yAxelOffSet;
  227. ray.fraction_ = 0.0f;
  228. }
  229. raysInitialized_ = true;
  230. CastRays();
  231. Vertex2D vertex0;
  232. Vertex2D vertex1;
  233. Vertex2D vertex2;
  234. Vertex2D vertex3;
  235. vertex0.color_ = vertex1.color_ = vertex2.color_ = vertex3.color_ = color_.ToUInt();
  236. vertex0.uv_.x_ = 1.0f;
  237. vertex2.uv_.x_ = 1.0 ;
  238. vertex1.uv_.x_ = 1.0f;
  239. vertex3.uv_.x_ = 1.0f;
  240. int vertexCount = (rayNum - 1) * 6;
  241. if (softShadows_ && castShadows_)
  242. vertexCount *= 2;
  243. if (vertices_.Size() != vertexCount)
  244. vertices_.Resize(vertexCount);
  245. Vertex2D* v = &vertices_[0];
  246. for (unsigned i = 0; i < rayNum - 1; i++) {
  247. Light2DRay& ray0 = rays_[i];
  248. Light2DRay& ray1 = rays_[i + 1];
  249. vertex0.position_.x_ = ray0.start_.x_;
  250. vertex0.position_.y_ = ray0.start_.y_;
  251. vertex1.position_.x_ = ray0.end_.x_;
  252. vertex1.position_.y_ = ray0.end_.y_;
  253. vertex2.position_.x_ = ray1.start_.x_;
  254. vertex2.position_.y_ = ray1.start_.y_;
  255. vertex3.position_.x_ = ray1.end_.x_;
  256. vertex3.position_.y_ = ray1.end_.y_;
  257. *v++ = vertex0;
  258. *v++ = vertex1;
  259. *v++ = vertex3;
  260. *v++ = vertex0;
  261. *v++ = vertex3;
  262. *v++ = vertex2;
  263. }
  264. if (softShadows_ && castShadows_)
  265. {
  266. // THIS CAN BE OPTIMIZED!
  267. for (unsigned i = 0; i < rays_.Size() - 1; i++) {
  268. Light2DRay& ray0 = rays_[i];
  269. Light2DRay& ray1 = rays_[i + 1];
  270. vertex0.position_ = Vector3( ray0.end_.x_, ray0.end_.y_, 0.0f);
  271. Vector2 v0 = (ray0.end_ - ray0.start_).Normalized();
  272. Vector2 v1 = (ray1.end_ - ray1.start_).Normalized();
  273. vertex1.position_ = Vector3( ray0.end_.x_ + v0.x_ * softShadowLength_,
  274. ray0.end_.y_ + v0.y_ * softShadowLength_, 0.0f);
  275. vertex2.position_ = Vector3( ray1.end_.x_ + v1.x_ * softShadowLength_,
  276. ray1.end_.y_ + v1.y_ * softShadowLength_, 0.0f);
  277. vertex3.position_ = Vector3( ray1.end_.x_, ray1.end_.y_, 0.0f);
  278. vertex0.color_ = 0;
  279. vertex3.color_ = 0;
  280. vertex0.uv_.x_ = 0;
  281. vertex3.uv_.x_ = 0;
  282. vertex1.color_ = 0;
  283. vertex2.color_ = 0;
  284. vertex1.uv_.x_ = 1.0;
  285. vertex2.uv_.x_ = 1.0;
  286. *v++ = vertex0;
  287. *v++ = vertex1;
  288. *v++ = vertex2;
  289. *v++ = vertex0;
  290. *v++ = vertex2;
  291. *v++ = vertex3;
  292. }
  293. }
  294. }
  295. PositionalLight2D::PositionalLight2D(Context* context) : Light2D(context)
  296. {
  297. }
  298. PositionalLight2D::~PositionalLight2D()
  299. {
  300. }
  301. void PositionalLight2D::RegisterObject(Context* context)
  302. {
  303. context->RegisterFactory<PositionalLight2D>(ATOMIC2D_CATEGORY);
  304. ATOMIC_COPY_BASE_ATTRIBUTES(Light2D);
  305. }
  306. void PositionalLight2D::UpdateVertices()
  307. {
  308. if (!lightgroup_ || !enabled_ || context_->GetEditorContext())
  309. {
  310. vertices_.Clear();
  311. return;
  312. }
  313. CastRays();
  314. Vertex2D vertex0;
  315. Vertex2D vertex1;
  316. Vertex2D vertex2;
  317. Vertex2D vertex3;
  318. vertex0.color_ = vertex1.color_ = vertex2.color_ = vertex3.color_ = color_.ToUInt();
  319. int vertexCount = (rays_.Size() - 1 ) * 3;
  320. if (softShadows_ && castShadows_)
  321. vertexCount += (rays_.Size() - 1) * 6;
  322. if (vertices_.Size() != vertexCount)
  323. vertices_.Resize(vertexCount);
  324. Vertex2D* v = &vertices_[0];
  325. for (unsigned i = 0; i < rays_.Size() - 1; i++) {
  326. Light2DRay& ray0 = rays_[i];
  327. Light2DRay& ray1 = rays_[i + 1];
  328. vertex0.position_.x_ = ray0.start_.x_;
  329. vertex0.position_.y_ = ray0.start_.y_;
  330. vertex1.position_.x_ = ray0.end_.x_;
  331. vertex1.position_.y_ = ray0.end_.y_;
  332. vertex2.position_.x_ = ray1.end_.x_;
  333. vertex2.position_.y_ = ray1.end_.y_;
  334. vertex0.uv_.x_ = 1.0f;
  335. vertex1.uv_.x_ = 1.0f - ray0.fraction_;
  336. vertex2.uv_.x_ = 1.0f - ray1.fraction_;
  337. *v++ = vertex0;
  338. *v++ = vertex1;
  339. *v++ = vertex2;
  340. }
  341. if (softShadows_ && castShadows_)
  342. {
  343. // THIS CAN BE OPTIMIZED!
  344. for (unsigned i = 0; i < rays_.Size() - 1; i++) {
  345. Light2DRay& ray0 = rays_[i];
  346. Light2DRay& ray1 = rays_[i + 1 == rays_.Size() ? 0 : i + 1];
  347. float s0 = (1.0f - ray0.fraction_);
  348. float s1 = (1.0f - ray1.fraction_);
  349. vertex0.position_.x_ = ray0.end_.x_;
  350. vertex0.position_.y_ = ray0.end_.y_;
  351. vertex1.position_.x_ = ray0.end_.x_ + s0 * softShadowLength_ * ray0.cos_;
  352. vertex1.position_.y_ = ray0.end_.y_ + s0 * softShadowLength_ * ray0.sin_;
  353. vertex2.position_.x_ = ray1.end_.x_ + s1 * softShadowLength_ * ray1.cos_;
  354. vertex2.position_.y_ = ray1.end_.y_ + s1 * softShadowLength_ * ray1.sin_;
  355. vertex3.position_.x_ = ray1.end_.x_;
  356. vertex3.position_.y_ = ray1.end_.y_;
  357. vertex1.uv_.x_ = 0;
  358. vertex2.uv_.x_ = 0;
  359. vertex1.color_ = 0x00000000;
  360. vertex2.color_ = 0x00000000;
  361. // darkness of shadow, we should break this all out of uint
  362. vertex0.uv_.x_ = s0 * .65f;
  363. vertex3.uv_.x_ = s1 * .65f;
  364. *v++ = vertex0;
  365. *v++ = vertex1;
  366. *v++ = vertex2;
  367. *v++ = vertex0;
  368. *v++ = vertex2;
  369. *v++ = vertex3;
  370. }
  371. }
  372. }
  373. PointLight2D::PointLight2D(Context* context) : PositionalLight2D(context),
  374. radius_(4.0f)
  375. {
  376. lightType_ = LIGHT2D_POINT;
  377. }
  378. PointLight2D::~PointLight2D()
  379. {
  380. }
  381. void PointLight2D::RegisterObject(Context* context)
  382. {
  383. context->RegisterFactory<PointLight2D>(ATOMIC2D_CATEGORY);
  384. ATOMIC_COPY_BASE_ATTRIBUTES(PositionalLight2D);
  385. ATOMIC_ACCESSOR_ATTRIBUTE("Radius", GetRadius, SetRadius, float, 4.0f, AM_DEFAULT);
  386. }
  387. void PointLight2D::UpdateVertices()
  388. {
  389. const Node* lightNode = GetNode();
  390. if (!lightgroup_ || !enabled_ || !lightNode || context_->GetEditorContext())
  391. {
  392. vertices_.Clear();
  393. return;
  394. }
  395. Vector2 start = lightNode->GetWorldPosition2D();
  396. float angleNum = 360.0f / float((rays_.Size() - 1));
  397. for (unsigned i = 0; i < rays_.Size(); i++) {
  398. float angle = angleNum * i;
  399. Light2DRay& ray = rays_[i];
  400. ray.start_ = start;
  401. ray.sin_ = Sin(angle);
  402. ray.cos_ = Cos(angle);
  403. ray.end_.x_ = ray.start_.x_ + radius_ * ray.cos_;
  404. ray.end_.y_ = ray.start_.y_ + radius_ * ray.sin_;
  405. ray.fraction_ = 1.0f;
  406. }
  407. raysInitialized_ = true;
  408. PositionalLight2D::UpdateVertices();
  409. }
  410. void Light2DGroup::RegisterObject(Context* context)
  411. {
  412. context->RegisterFactory<Light2DGroup>(ATOMIC2D_CATEGORY);
  413. ATOMIC_COPY_BASE_ATTRIBUTES(Drawable2D);
  414. }
  415. void Light2DGroup::OnSceneSet(Scene* scene)
  416. {
  417. if (scene && node_ && !context_->GetEditorContext())
  418. {
  419. physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld2D>();
  420. Zone* zone = scene->GetComponent<Zone>();
  421. if (zone)
  422. SetAmbientColor(zone->GetAmbientColor());
  423. renderer_ = node_->GetOrCreateComponent<Renderer2D>();
  424. renderer_->SetTemporary(true);
  425. renderer_->SetUseTris(true);
  426. if (light2DMaterial_.Null())
  427. CreateLight2DMaterial();
  428. if (IsEnabledEffective())
  429. renderer_->AddDrawable(this);
  430. node_->AddListener(this);
  431. }
  432. else
  433. {
  434. if (renderer_)
  435. renderer_->RemoveDrawable(this);
  436. }
  437. }
  438. Light2DGroup::Light2DGroup(Context* context) : Drawable2D(context),
  439. lightgroupID_(0),
  440. ambientColor_(0, 0, 0, 0),
  441. frustum_(0)
  442. {
  443. sourceBatches_.Resize(1);
  444. sourceBatches_[0].owner_ = this;
  445. SubscribeToEvent(E_BEGINRENDERING, ATOMIC_HANDLER(Light2DGroup, HandleBeginRendering));
  446. SubscribeToEvent(E_BEGINVIEWUPDATE, ATOMIC_HANDLER(Light2DGroup, HandleBeginViewUpdate));
  447. }
  448. Light2DGroup::~Light2DGroup()
  449. {
  450. Renderer* renderer = GetSubsystem<Renderer>();
  451. if (renderer)
  452. {
  453. Viewport* viewport = renderer->GetViewport(0);
  454. if (viewport)
  455. {
  456. RenderPath* renderpath = viewport->GetRenderPath();
  457. if (renderpath)
  458. renderpath->RemoveCommands("Light2D");
  459. }
  460. }
  461. }
  462. void Light2DGroup::HandleBeginViewUpdate(StringHash eventType, VariantMap& eventData)
  463. {
  464. using namespace BeginViewUpdate;
  465. Scene* scene = GetScene();
  466. // Check that we are updating the correct scene
  467. if (scene != eventData[P_SCENE].GetPtr())
  468. return;
  469. Camera* camera = static_cast<Camera*>(eventData[P_CAMERA].GetPtr());
  470. frustum_ = &camera->GetFrustum();
  471. if (camera->IsOrthographic())// && camera->GetNode()->GetWorldDirection() == Vector3::FORWARD)
  472. {
  473. // Define bounding box with min and max points
  474. // todo: handle rotation
  475. frustumBoundingBox_.Define(frustum_->vertices_[2], frustum_->vertices_[4]);
  476. }
  477. }
  478. void Light2DGroup::HandleBeginRendering(StringHash eventType, VariantMap& eventData)
  479. {
  480. sourceBatchesDirty_ = true;
  481. }
  482. void Light2DGroup::OnWorldBoundingBoxUpdate()
  483. {
  484. boundingBox_.Define(-M_LARGE_VALUE, M_LARGE_VALUE);
  485. worldBoundingBox_.Define(-M_LARGE_VALUE, M_LARGE_VALUE);
  486. }
  487. void Light2DGroup::OnDrawOrderChanged()
  488. {
  489. sourceBatches_[0].drawOrder_ = GetDrawOrder();
  490. }
  491. void Light2DGroup::UpdateSourceBatches()
  492. {
  493. if (!sourceBatchesDirty_)
  494. return;
  495. Vector<Vertex2D>& vertices = sourceBatches_[0].vertices_;
  496. vertices.Clear();
  497. for (Vector<WeakPtr<Light2D> >::Iterator itr = lights_.Begin(); itr != lights_.End(); itr++)
  498. {
  499. Light2D* light = *itr;
  500. if (!light->IsEnabled())
  501. continue;
  502. light->UpdateVertices();
  503. light->AddVertices(vertices);
  504. }
  505. sourceBatchesDirty_ = false;
  506. }
  507. void Light2DGroup::AddLight2D(Light2D* light)
  508. {
  509. Vector<WeakPtr<Light2D>>::Iterator itr = lights_.Find(WeakPtr<Light2D>(light));
  510. if (itr != lights_.End())
  511. return;
  512. lights_.Push(WeakPtr<Light2D>(light));
  513. }
  514. void Light2DGroup::RemoveLight2D(Light2D* light)
  515. {
  516. Vector<WeakPtr<Light2D>>::Iterator itr = lights_.Find(WeakPtr<Light2D>(light));
  517. if (itr != lights_.End())
  518. lights_.Erase(itr);
  519. }
  520. void Light2DGroup::SetAmbientColor(const Color& color)
  521. {
  522. if (color == ambientColor_)
  523. return;
  524. ambientColor_ = color;
  525. Renderer* renderer = GetSubsystem<Renderer>();
  526. // only on main viewport atm and viewport must first be set
  527. if (renderer)
  528. {
  529. Viewport* viewport = renderer->GetViewport(0);
  530. if (viewport)
  531. {
  532. RenderPath* renderpath = viewport->GetRenderPath();
  533. renderpath->SetShaderParameter("ShadowAmbient", ambientColor_);
  534. }
  535. }
  536. }
  537. void Light2DGroup::CreateLight2DMaterial()
  538. {
  539. if (context_->GetEditorContext())
  540. return;
  541. Renderer* renderer = GetSubsystem<Renderer>();
  542. Viewport* viewport = renderer->GetViewport(0);
  543. RenderPath* renderpath = viewport->GetRenderPath();
  544. RenderTargetInfo ntarget;
  545. ntarget.enabled_ = true;
  546. ntarget.name_ = "light2dtarget";
  547. ntarget.tag_ = "Light2D";
  548. ntarget.format_ = Graphics::GetRGBAFormat();
  549. ntarget.sizeMode_ = SIZE_VIEWPORTDIVISOR;
  550. ntarget.size_ = Vector2(4, 4);
  551. // try true
  552. ntarget.filtered_ = false;
  553. renderpath->AddRenderTarget(ntarget);
  554. RenderPathCommand clearCommand;
  555. clearCommand.tag_ = "Light2D";
  556. clearCommand.type_ = CMD_CLEAR;
  557. clearCommand.clearColor_ = Color(0, 0, 0, 0);
  558. clearCommand.clearFlags_ = CLEAR_COLOR;
  559. clearCommand.enabled_ = true;
  560. clearCommand.SetNumOutputs(1);
  561. clearCommand.SetOutputName(0, "light2dtarget");
  562. renderpath->AddCommand(clearCommand);
  563. RenderPathCommand passCommand;
  564. passCommand.tag_ = "Light2D";
  565. passCommand.type_ = CMD_SCENEPASS;
  566. passCommand.pass_ = "light2d";
  567. passCommand.enabled_ = true;
  568. passCommand.SetNumOutputs(1);
  569. passCommand.SetOutputName(0, "light2dtarget");
  570. renderpath->AddCommand(passCommand);
  571. ResourceCache* cache = GetSubsystem<ResourceCache>();
  572. XMLFile* light2DBlur = cache->GetResource<XMLFile>("PostProcess/Light2DBlur.xml");
  573. renderpath->Append(light2DBlur);
  574. RenderPathCommand copyCommand;
  575. copyCommand.enabled_ = true;
  576. copyCommand.tag_ = "Light2D";
  577. copyCommand.type_ = CMD_QUAD;
  578. copyCommand.vertexShaderName_ = "Shadow2D";
  579. copyCommand.pixelShaderName_ = "Shadow2D";
  580. copyCommand.SetTextureName(TU_DIFFUSE, "viewport");
  581. copyCommand.SetTextureName(TU_EMISSIVE, "light2dtarget");
  582. copyCommand.SetShaderParameter("ShadowAmbient", ambientColor_);
  583. copyCommand.SetNumOutputs(1);
  584. copyCommand.SetOutputName(0, "viewport");
  585. renderpath->AddCommand(copyCommand);
  586. light2DMaterial_ = new Material(context_);
  587. light2DMaterial_->SetName("Light2DMaterial");
  588. Technique* tech = new Technique(context_);
  589. Pass* pass = tech->CreatePass("light2d");
  590. pass->SetBlendMode(BLEND_ADDALPHA);
  591. pass->SetDepthTestMode(CMP_ALWAYS);
  592. pass->SetVertexShader("Light2D");
  593. pass->SetPixelShader("Light2D");
  594. pass->SetDepthWrite(false);
  595. light2DMaterial_->SetTechnique(0, tech);
  596. light2DMaterial_->SetCullMode(CULL_NONE);
  597. sourceBatches_[0].material_ = light2DMaterial_;
  598. }
  599. }