Light2D.cpp 21 KB

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