LightSystem.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. #include "LightSystem.h"
  2. #include <cassert>
  3. #include <iostream>
  4. #include <cmath>
  5. using namespace ltbl;
  6. void LightSystem::getPenumbrasPoint(std::vector<Penumbra> &penumbras, std::vector<int> &innerBoundaryIndices, std::vector<sf::Vector2f> &innerBoundaryVectors, std::vector<int> &outerBoundaryIndices, std::vector<sf::Vector2f> &outerBoundaryVectors, const sf::ConvexShape &shape, const sf::Vector2f &sourceCenter, float sourceRadius) {
  7. const int numPoints = shape.getPointCount();
  8. std::vector<bool> bothEdgesBoundaryWindings;
  9. bothEdgesBoundaryWindings.reserve(2);
  10. std::vector<bool> oneEdgeBoundaryWindings;
  11. oneEdgeBoundaryWindings.reserve(2);
  12. // Calculate front and back facing sides
  13. std::vector<bool> facingFrontBothEdges;
  14. facingFrontBothEdges.reserve(numPoints);
  15. std::vector<bool> facingFrontOneEdge;
  16. facingFrontOneEdge.reserve(numPoints);
  17. for (int i = 0; i < numPoints; i++) {
  18. sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(i));
  19. sf::Vector2f nextPoint;
  20. if (i < numPoints - 1)
  21. nextPoint = shape.getTransform().transformPoint(shape.getPoint(i + 1));
  22. else
  23. nextPoint = shape.getTransform().transformPoint(shape.getPoint(0));
  24. sf::Vector2f firstEdgeRay;
  25. sf::Vector2f secondEdgeRay;
  26. sf::Vector2f firstNextEdgeRay;
  27. sf::Vector2f secondNextEdgeRay;
  28. {
  29. sf::Vector2f sourceToPoint = point - sourceCenter;
  30. sf::Vector2f perpendicularOffset(-sourceToPoint.y, sourceToPoint.x);
  31. perpendicularOffset = vectorNormalize(perpendicularOffset);
  32. perpendicularOffset *= sourceRadius;
  33. firstEdgeRay = point - (sourceCenter - perpendicularOffset);
  34. secondEdgeRay = point - (sourceCenter + perpendicularOffset);
  35. }
  36. {
  37. sf::Vector2f sourceToPoint = nextPoint - sourceCenter;
  38. sf::Vector2f perpendicularOffset(-sourceToPoint.y, sourceToPoint.x);
  39. perpendicularOffset = vectorNormalize(perpendicularOffset);
  40. perpendicularOffset *= sourceRadius;
  41. firstNextEdgeRay = nextPoint - (sourceCenter - perpendicularOffset);
  42. secondNextEdgeRay = nextPoint - (sourceCenter + perpendicularOffset);
  43. }
  44. sf::Vector2f pointToNextPoint = nextPoint - point;
  45. sf::Vector2f normal = vectorNormalize(sf::Vector2f(-pointToNextPoint.y, pointToNextPoint.x));
  46. // Front facing, mark it
  47. facingFrontBothEdges.push_back((vectorDot(firstEdgeRay, normal) > 0.0f && vectorDot(secondEdgeRay, normal) > 0.0f) || (vectorDot(firstNextEdgeRay, normal) > 0.0f && vectorDot(secondNextEdgeRay, normal) > 0.0f));
  48. facingFrontOneEdge.push_back((vectorDot(firstEdgeRay, normal) > 0.0f || vectorDot(secondEdgeRay, normal) > 0.0f) || vectorDot(firstNextEdgeRay, normal) > 0.0f || vectorDot(secondNextEdgeRay, normal) > 0.0f);
  49. }
  50. // Go through front/back facing list. Where the facing direction switches, there is a boundary
  51. for (int i = 1; i < numPoints; i++)
  52. if (facingFrontBothEdges[i] != facingFrontBothEdges[i - 1]) {
  53. innerBoundaryIndices.push_back(i);
  54. bothEdgesBoundaryWindings.push_back(facingFrontBothEdges[i]);
  55. }
  56. // Check looping indices separately
  57. if (facingFrontBothEdges[0] != facingFrontBothEdges[numPoints - 1]) {
  58. innerBoundaryIndices.push_back(0);
  59. bothEdgesBoundaryWindings.push_back(facingFrontBothEdges[0]);
  60. }
  61. // Go through front/back facing list. Where the facing direction switches, there is a boundary
  62. for (int i = 1; i < numPoints; i++)
  63. if (facingFrontOneEdge[i] != facingFrontOneEdge[i - 1]) {
  64. outerBoundaryIndices.push_back(i);
  65. oneEdgeBoundaryWindings.push_back(facingFrontOneEdge[i]);
  66. }
  67. // Check looping indices separately
  68. if (facingFrontOneEdge[0] != facingFrontOneEdge[numPoints - 1]) {
  69. outerBoundaryIndices.push_back(0);
  70. oneEdgeBoundaryWindings.push_back(facingFrontOneEdge[0]);
  71. }
  72. // Compute outer boundary vectors
  73. for (unsigned bi = 0; bi < outerBoundaryIndices.size(); bi++) {
  74. int penumbraIndex = outerBoundaryIndices[bi];
  75. bool winding = oneEdgeBoundaryWindings[bi];
  76. sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex));
  77. sf::Vector2f sourceToPoint = point - sourceCenter;
  78. sf::Vector2f perpendicularOffset(-sourceToPoint.y, sourceToPoint.x);
  79. perpendicularOffset = vectorNormalize(perpendicularOffset);
  80. perpendicularOffset *= sourceRadius;
  81. sf::Vector2f firstEdgeRay = point - (sourceCenter + perpendicularOffset);
  82. sf::Vector2f secondEdgeRay = point - (sourceCenter - perpendicularOffset);
  83. // Add boundary vector
  84. outerBoundaryVectors.push_back(winding ? firstEdgeRay : secondEdgeRay);
  85. }
  86. for (unsigned bi = 0; bi < innerBoundaryIndices.size(); bi++) {
  87. int penumbraIndex = innerBoundaryIndices[bi];
  88. bool winding = bothEdgesBoundaryWindings[bi];
  89. sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex));
  90. sf::Vector2f sourceToPoint = point - sourceCenter;
  91. sf::Vector2f perpendicularOffset(-sourceToPoint.y, sourceToPoint.x);
  92. perpendicularOffset = vectorNormalize(perpendicularOffset);
  93. perpendicularOffset *= sourceRadius;
  94. sf::Vector2f firstEdgeRay = point - (sourceCenter + perpendicularOffset);
  95. sf::Vector2f secondEdgeRay = point - (sourceCenter - perpendicularOffset);
  96. // Add boundary vector
  97. innerBoundaryVectors.push_back(winding ? secondEdgeRay : firstEdgeRay);
  98. sf::Vector2f outerBoundaryVector = winding ? firstEdgeRay : secondEdgeRay;
  99. if (innerBoundaryIndices.size() == 1)
  100. innerBoundaryVectors.push_back(outerBoundaryVector);
  101. // Add penumbras
  102. bool hasPrevPenumbra = false;
  103. sf::Vector2f prevPenumbraLightEdgeVector;
  104. float prevBrightness = 1.0f;
  105. int counter = 0;
  106. while (penumbraIndex != -1) {
  107. sf::Vector2f nextPoint;
  108. int nextPointIndex;
  109. if (penumbraIndex < numPoints - 1) {
  110. nextPointIndex = penumbraIndex + 1;
  111. nextPoint = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex + 1));
  112. }
  113. else {
  114. nextPointIndex = 0;
  115. nextPoint = shape.getTransform().transformPoint(shape.getPoint(0));
  116. }
  117. sf::Vector2f pointToNextPoint = nextPoint - point;
  118. sf::Vector2f prevPoint;
  119. int prevPointIndex;
  120. if (penumbraIndex > 0) {
  121. prevPointIndex = penumbraIndex - 1;
  122. prevPoint = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex - 1));
  123. }
  124. else {
  125. prevPointIndex = numPoints - 1;
  126. prevPoint = shape.getTransform().transformPoint(shape.getPoint(numPoints - 1));
  127. }
  128. sf::Vector2f pointToPrevPoint = prevPoint - point;
  129. LightSystem::Penumbra penumbra;
  130. penumbra._source = point;
  131. if (!winding) {
  132. if (hasPrevPenumbra)
  133. penumbra._lightEdge = prevPenumbraLightEdgeVector;
  134. else
  135. penumbra._lightEdge = innerBoundaryVectors.back();
  136. penumbra._darkEdge = outerBoundaryVector;
  137. penumbra._lightBrightness = prevBrightness;
  138. // Next point, check for intersection
  139. float intersectionAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(pointToNextPoint)));
  140. float penumbraAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(penumbra._darkEdge)));
  141. if (intersectionAngle < penumbraAngle) {
  142. prevBrightness = penumbra._darkBrightness = intersectionAngle / penumbraAngle;
  143. assert(prevBrightness >= 0.0f && prevBrightness <= 1.0f);
  144. penumbra._darkEdge = pointToNextPoint;
  145. penumbraIndex = nextPointIndex;
  146. if (hasPrevPenumbra) {
  147. std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness);
  148. std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness);
  149. }
  150. hasPrevPenumbra = true;
  151. prevPenumbraLightEdgeVector = penumbra._darkEdge;
  152. point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex));
  153. sourceToPoint = point - sourceCenter;
  154. perpendicularOffset = sf::Vector2f(-sourceToPoint.y, sourceToPoint.x);
  155. perpendicularOffset = vectorNormalize(perpendicularOffset);
  156. perpendicularOffset *= sourceRadius;
  157. firstEdgeRay = point - (sourceCenter + perpendicularOffset);
  158. secondEdgeRay = point - (sourceCenter - perpendicularOffset);
  159. outerBoundaryVector = secondEdgeRay;
  160. if (!outerBoundaryVectors.empty()) {
  161. outerBoundaryVectors[0] = penumbra._darkEdge;
  162. outerBoundaryIndices[0] = penumbraIndex;
  163. }
  164. }
  165. else {
  166. penumbra._darkBrightness = 0.0f;
  167. if (hasPrevPenumbra) {
  168. std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness);
  169. std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness);
  170. }
  171. hasPrevPenumbra = false;
  172. if (!outerBoundaryVectors.empty()) {
  173. outerBoundaryVectors[0] = penumbra._darkEdge;
  174. outerBoundaryIndices[0] = penumbraIndex;
  175. }
  176. penumbraIndex = -1;
  177. }
  178. }
  179. else {
  180. if (hasPrevPenumbra)
  181. penumbra._lightEdge = prevPenumbraLightEdgeVector;
  182. else
  183. penumbra._lightEdge = innerBoundaryVectors.back();
  184. penumbra._darkEdge = outerBoundaryVector;
  185. penumbra._lightBrightness = prevBrightness;
  186. // Next point, check for intersection
  187. float intersectionAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(pointToPrevPoint)));
  188. float penumbraAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(penumbra._darkEdge)));
  189. if (intersectionAngle < penumbraAngle) {
  190. prevBrightness = penumbra._darkBrightness = intersectionAngle / penumbraAngle;
  191. assert(prevBrightness >= 0.0f && prevBrightness <= 1.0f);
  192. penumbra._darkEdge = pointToPrevPoint;
  193. penumbraIndex = prevPointIndex;
  194. if (hasPrevPenumbra) {
  195. std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness);
  196. std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness);
  197. }
  198. hasPrevPenumbra = true;
  199. prevPenumbraLightEdgeVector = penumbra._darkEdge;
  200. point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex));
  201. sourceToPoint = point - sourceCenter;
  202. perpendicularOffset = sf::Vector2f(-sourceToPoint.y, sourceToPoint.x);
  203. perpendicularOffset = vectorNormalize(perpendicularOffset);
  204. perpendicularOffset *= sourceRadius;
  205. firstEdgeRay = point - (sourceCenter + perpendicularOffset);
  206. secondEdgeRay = point - (sourceCenter - perpendicularOffset);
  207. outerBoundaryVector = firstEdgeRay;
  208. if (!outerBoundaryVectors.empty()) {
  209. outerBoundaryVectors[1] = penumbra._darkEdge;
  210. outerBoundaryIndices[1] = penumbraIndex;
  211. }
  212. }
  213. else {
  214. penumbra._darkBrightness = 0.0f;
  215. if (hasPrevPenumbra) {
  216. std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness);
  217. std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness);
  218. }
  219. hasPrevPenumbra = false;
  220. if (!outerBoundaryVectors.empty()) {
  221. outerBoundaryVectors[1] = penumbra._darkEdge;
  222. outerBoundaryIndices[1] = penumbraIndex;
  223. }
  224. penumbraIndex = -1;
  225. }
  226. }
  227. penumbras.push_back(penumbra);
  228. counter++;
  229. }
  230. }
  231. }
  232. void LightSystem::getPenumbrasDirection(std::vector<Penumbra> &penumbras, std::vector<int> &innerBoundaryIndices, std::vector<sf::Vector2f> &innerBoundaryVectors, std::vector<int> &outerBoundaryIndices, std::vector<sf::Vector2f> &outerBoundaryVectors, const sf::ConvexShape &shape, const sf::Vector2f &sourceDirection, float sourceRadius, float sourceDistance) {
  233. const int numPoints = shape.getPointCount();
  234. innerBoundaryIndices.reserve(2);
  235. innerBoundaryVectors.reserve(2);
  236. penumbras.reserve(2);
  237. std::vector<bool> bothEdgesBoundaryWindings;
  238. bothEdgesBoundaryWindings.reserve(2);
  239. // Calculate front and back facing sides
  240. std::vector<bool> facingFrontBothEdges;
  241. facingFrontBothEdges.reserve(numPoints);
  242. std::vector<bool> facingFrontOneEdge;
  243. facingFrontOneEdge.reserve(numPoints);
  244. for (int i = 0; i < numPoints; i++) {
  245. sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(i));
  246. sf::Vector2f nextPoint;
  247. if (i < numPoints - 1)
  248. nextPoint = shape.getTransform().transformPoint(shape.getPoint(i + 1));
  249. else
  250. nextPoint = shape.getTransform().transformPoint(shape.getPoint(0));
  251. sf::Vector2f firstEdgeRay;
  252. sf::Vector2f secondEdgeRay;
  253. sf::Vector2f firstNextEdgeRay;
  254. sf::Vector2f secondNextEdgeRay;
  255. sf::Vector2f perpendicularOffset(-sourceDirection.y, sourceDirection.x);
  256. perpendicularOffset = vectorNormalize(perpendicularOffset);
  257. perpendicularOffset *= sourceRadius;
  258. firstEdgeRay = point - (point - sourceDirection * sourceDistance - perpendicularOffset);
  259. secondEdgeRay = point - (point - sourceDirection * sourceDistance + perpendicularOffset);
  260. firstNextEdgeRay = nextPoint - (point - sourceDirection * sourceDistance - perpendicularOffset);
  261. secondNextEdgeRay = nextPoint - (point - sourceDirection * sourceDistance + perpendicularOffset);
  262. sf::Vector2f pointToNextPoint = nextPoint - point;
  263. sf::Vector2f normal = vectorNormalize(sf::Vector2f(-pointToNextPoint.y, pointToNextPoint.x));
  264. // Front facing, mark it
  265. facingFrontBothEdges.push_back((vectorDot(firstEdgeRay, normal) > 0.0f && vectorDot(secondEdgeRay, normal) > 0.0f) || (vectorDot(firstNextEdgeRay, normal) > 0.0f && vectorDot(secondNextEdgeRay, normal) > 0.0f));
  266. facingFrontOneEdge.push_back((vectorDot(firstEdgeRay, normal) > 0.0f || vectorDot(secondEdgeRay, normal) > 0.0f) || vectorDot(firstNextEdgeRay, normal) > 0.0f || vectorDot(secondNextEdgeRay, normal) > 0.0f);
  267. }
  268. // Go through front/back facing list. Where the facing direction switches, there is a boundary
  269. for (int i = 1; i < numPoints; i++)
  270. if (facingFrontBothEdges[i] != facingFrontBothEdges[i - 1]) {
  271. innerBoundaryIndices.push_back(i);
  272. bothEdgesBoundaryWindings.push_back(facingFrontBothEdges[i]);
  273. }
  274. // Check looping indices separately
  275. if (facingFrontBothEdges[0] != facingFrontBothEdges[numPoints - 1]) {
  276. innerBoundaryIndices.push_back(0);
  277. bothEdgesBoundaryWindings.push_back(facingFrontBothEdges[0]);
  278. }
  279. // Go through front/back facing list. Where the facing direction switches, there is a boundary
  280. for (int i = 1; i < numPoints; i++)
  281. if (facingFrontOneEdge[i] != facingFrontOneEdge[i - 1])
  282. outerBoundaryIndices.push_back(i);
  283. // Check looping indices separately
  284. if (facingFrontOneEdge[0] != facingFrontOneEdge[numPoints - 1])
  285. outerBoundaryIndices.push_back(0);
  286. for (unsigned bi = 0; bi < innerBoundaryIndices.size(); bi++) {
  287. int penumbraIndex = innerBoundaryIndices[bi];
  288. bool winding = bothEdgesBoundaryWindings[bi];
  289. sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex));
  290. sf::Vector2f perpendicularOffset(-sourceDirection.y, sourceDirection.x);
  291. perpendicularOffset = vectorNormalize(perpendicularOffset);
  292. perpendicularOffset *= sourceRadius;
  293. sf::Vector2f firstEdgeRay = point - (point - sourceDirection * sourceDistance + perpendicularOffset);
  294. sf::Vector2f secondEdgeRay = point - (point - sourceDirection * sourceDistance - perpendicularOffset);
  295. // Add boundary vector
  296. innerBoundaryVectors.push_back(winding ? secondEdgeRay : firstEdgeRay);
  297. sf::Vector2f outerBoundaryVector = winding ? firstEdgeRay : secondEdgeRay;
  298. outerBoundaryVectors.push_back(outerBoundaryVector);
  299. // Add penumbras
  300. bool hasPrevPenumbra = false;
  301. sf::Vector2f prevPenumbraLightEdgeVector;
  302. float prevBrightness = 1.0f;
  303. int counter = 0;
  304. while (penumbraIndex != -1) {
  305. sf::Vector2f nextPoint;
  306. int nextPointIndex;
  307. if (penumbraIndex < numPoints - 1) {
  308. nextPointIndex = penumbraIndex + 1;
  309. nextPoint = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex + 1));
  310. }
  311. else {
  312. nextPointIndex = 0;
  313. nextPoint = shape.getTransform().transformPoint(shape.getPoint(0));
  314. }
  315. sf::Vector2f pointToNextPoint = nextPoint - point;
  316. sf::Vector2f prevPoint;
  317. int prevPointIndex;
  318. if (penumbraIndex > 0) {
  319. prevPointIndex = penumbraIndex - 1;
  320. prevPoint = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex - 1));
  321. }
  322. else {
  323. prevPointIndex = numPoints - 1;
  324. prevPoint = shape.getTransform().transformPoint(shape.getPoint(numPoints - 1));
  325. }
  326. sf::Vector2f pointToPrevPoint = prevPoint - point;
  327. LightSystem::Penumbra penumbra;
  328. penumbra._source = point;
  329. if (!winding) {
  330. if (hasPrevPenumbra)
  331. penumbra._lightEdge = prevPenumbraLightEdgeVector;
  332. else
  333. penumbra._lightEdge = innerBoundaryVectors.back();
  334. penumbra._darkEdge = outerBoundaryVector;
  335. penumbra._lightBrightness = prevBrightness;
  336. // Next point, check for intersection
  337. float intersectionAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(pointToNextPoint)));
  338. float penumbraAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(penumbra._darkEdge)));
  339. if (intersectionAngle < penumbraAngle) {
  340. prevBrightness = penumbra._darkBrightness = intersectionAngle / penumbraAngle;
  341. assert(prevBrightness >= 0.0f && prevBrightness <= 1.0f);
  342. penumbra._darkEdge = pointToNextPoint;
  343. penumbraIndex = nextPointIndex;
  344. if (hasPrevPenumbra) {
  345. std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness);
  346. std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness);
  347. }
  348. hasPrevPenumbra = true;
  349. prevPenumbraLightEdgeVector = penumbra._darkEdge;
  350. point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex));
  351. perpendicularOffset = sf::Vector2f(-sourceDirection.y, sourceDirection.x);
  352. perpendicularOffset = vectorNormalize(perpendicularOffset);
  353. perpendicularOffset *= sourceRadius;
  354. firstEdgeRay = point - (point - sourceDirection * sourceDistance + perpendicularOffset);
  355. secondEdgeRay = point - (point - sourceDirection * sourceDistance - perpendicularOffset);
  356. outerBoundaryVector = secondEdgeRay;
  357. }
  358. else {
  359. penumbra._darkBrightness = 0.0f;
  360. if (hasPrevPenumbra) {
  361. std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness);
  362. std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness);
  363. }
  364. hasPrevPenumbra = false;
  365. penumbraIndex = -1;
  366. }
  367. }
  368. else {
  369. if (hasPrevPenumbra)
  370. penumbra._lightEdge = prevPenumbraLightEdgeVector;
  371. else
  372. penumbra._lightEdge = innerBoundaryVectors.back();
  373. penumbra._darkEdge = outerBoundaryVector;
  374. penumbra._lightBrightness = prevBrightness;
  375. // Next point, check for intersection
  376. float intersectionAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(pointToPrevPoint)));
  377. float penumbraAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(penumbra._darkEdge)));
  378. if (intersectionAngle < penumbraAngle) {
  379. prevBrightness = penumbra._darkBrightness = intersectionAngle / penumbraAngle;
  380. assert(prevBrightness >= 0.0f && prevBrightness <= 1.0f);
  381. penumbra._darkEdge = pointToPrevPoint;
  382. penumbraIndex = prevPointIndex;
  383. if (hasPrevPenumbra) {
  384. std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness);
  385. std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness);
  386. }
  387. hasPrevPenumbra = true;
  388. prevPenumbraLightEdgeVector = penumbra._darkEdge;
  389. point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex));
  390. perpendicularOffset = sf::Vector2f(-sourceDirection.y, sourceDirection.x);
  391. perpendicularOffset = vectorNormalize(perpendicularOffset);
  392. perpendicularOffset *= sourceRadius;
  393. firstEdgeRay = point - (point - sourceDirection * sourceDistance + perpendicularOffset);
  394. secondEdgeRay = point - (point - sourceDirection * sourceDistance - perpendicularOffset);
  395. outerBoundaryVector = firstEdgeRay;
  396. }
  397. else {
  398. penumbra._darkBrightness = 0.0f;
  399. if (hasPrevPenumbra) {
  400. std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness);
  401. std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness);
  402. }
  403. hasPrevPenumbra = false;
  404. penumbraIndex = -1;
  405. }
  406. }
  407. penumbras.push_back(penumbra);
  408. counter++;
  409. }
  410. }
  411. }
  412. void LightSystem::create(const sf::FloatRect& rootRegion, const sf::Vector2u& imageSize,
  413. const sf::Texture& penumbraTexture,
  414. sf::Shader& unshadowShader, sf::Shader& lightOverShapeShader, sf::Shader& normalsShader)
  415. {
  416. _shapeQuadtree.create(rootRegion);
  417. _lightPointEmissionQuadtree.create(rootRegion);
  418. _lightTempTexture.create(imageSize.x, imageSize.y);
  419. _emissionTempTexture.create(imageSize.x, imageSize.y);
  420. _antumbraTempTexture.create(imageSize.x, imageSize.y);
  421. _compositionTexture.create(imageSize.x, imageSize.y);
  422. _normalsTexture.create(imageSize.x, imageSize.y);
  423. normalsTargetClear();
  424. sf::Vector2f targetSizeInv = sf::Vector2f(1.0f / imageSize.x, 1.0f / imageSize.y);
  425. unshadowShader.setParameter("penumbraTexture", penumbraTexture);
  426. lightOverShapeShader.setParameter("emissionTexture", _emissionTempTexture.getTexture());
  427. lightOverShapeShader.setParameter("targetSizeInv", targetSizeInv);
  428. normalsShader.setParameter("normalsTexture", _normalsTexture.getTexture());
  429. normalsShader.setParameter("targetSize", imageSize.x, imageSize.y);
  430. normalsShader.setParameter("lightTexture", sf::Shader::CurrentTexture);
  431. }
  432. void LightSystem::render(const sf::View &view, sf::Shader &unshadowShader, sf::Shader &lightOverShapeShader, sf::Shader& normalsShader)
  433. {
  434. _compositionTexture.clear(_ambientColor);
  435. _compositionTexture.setView(_compositionTexture.getDefaultView());
  436. // Get bounding rectangle of view
  437. sf::FloatRect viewBounds = sf::FloatRect(view.getCenter().x, view.getCenter().y, 0.0f, 0.0f);
  438. sf::FloatRect centeredViewBounds = rectRecenter(viewBounds, sf::Vector2f(0.0f, 0.0f));
  439. _lightTempTexture.setView(view);
  440. viewBounds = rectExpand(viewBounds, _lightTempTexture.mapPixelToCoords(sf::Vector2i(0, 0)));
  441. viewBounds = rectExpand(viewBounds, _lightTempTexture.mapPixelToCoords(sf::Vector2i(_lightTempTexture.getSize().x, 0)));
  442. viewBounds = rectExpand(viewBounds, _lightTempTexture.mapPixelToCoords(sf::Vector2i(_lightTempTexture.getSize().x, _lightTempTexture.getSize().y)));
  443. viewBounds = rectExpand(viewBounds, _lightTempTexture.mapPixelToCoords(sf::Vector2i(0, _lightTempTexture.getSize().y)));
  444. std::vector<QuadtreeOccupant*> viewPointEmissionLights;
  445. _lightPointEmissionQuadtree.queryRegion(viewPointEmissionLights, viewBounds);
  446. sf::RenderStates compoRenderStates;
  447. compoRenderStates.blendMode = sf::BlendAdd;
  448. //----- Point lights
  449. std::vector<QuadtreeOccupant*> lightShapes;
  450. sf::Sprite lightTempSprite(_lightTempTexture.getTexture());
  451. for (auto occupant : viewPointEmissionLights) {
  452. auto pPointEmissionLight = static_cast<LightPointEmission*>(occupant);
  453. // Query shapes this light is affected by
  454. lightShapes.clear();
  455. _shapeQuadtree.queryRegion(lightShapes, pPointEmissionLight->getAABB());
  456. pPointEmissionLight->render(view, _lightTempTexture, _emissionTempTexture, _antumbraTempTexture, lightShapes, unshadowShader, lightOverShapeShader, _normalsEnabled, normalsShader);
  457. _compositionTexture.draw(lightTempSprite, compoRenderStates);
  458. }
  459. //----- Direction lights
  460. for (const auto& directionEmissionLight : _directionEmissionLights) {
  461. LightDirectionEmission* pDirectionEmissionLight = directionEmissionLight.get();
  462. float maxDim = std::max(centeredViewBounds.width, centeredViewBounds.height);
  463. sf::FloatRect extendedViewBounds = rectFromBounds(sf::Vector2f(-maxDim, -maxDim) * _directionEmissionRadiusMultiplier,
  464. sf::Vector2f(maxDim, maxDim) * _directionEmissionRadiusMultiplier + sf::Vector2f(_directionEmissionRange, 0.0f));
  465. float shadowExtension = vectorMagnitude(rectLowerBound(centeredViewBounds)) * _directionEmissionRadiusMultiplier * 2.0f;
  466. sf::ConvexShape directionShape = shapeFromRect(extendedViewBounds);
  467. directionShape.setPosition(view.getCenter());
  468. sf::Vector2f normalizedCastDirection = vectorNormalize(pDirectionEmissionLight->_castDirection);
  469. directionShape.setRotation(_radToDeg * std::atan2(normalizedCastDirection.y, normalizedCastDirection.x));
  470. std::vector<QuadtreeOccupant*> viewLightShapes;
  471. _shapeQuadtree.queryShape(viewLightShapes, directionShape);
  472. pDirectionEmissionLight->render(view, _lightTempTexture, _antumbraTempTexture, viewLightShapes, unshadowShader, shadowExtension);
  473. sf::Sprite sprite;
  474. sprite.setTexture(_lightTempTexture.getTexture());
  475. _compositionTexture.draw(sprite, compoRenderStates);
  476. // TODO Normals
  477. }
  478. _compositionTexture.display();
  479. }
  480. LightShape* LightSystem::allocateShape()
  481. {
  482. return _lightShapesPool.newElement();
  483. }
  484. void LightSystem::deallocateShape(LightShape* pLightShape)
  485. {
  486. _lightShapesPool.deleteElement(pLightShape);
  487. }
  488. void LightSystem::addShape(LightShape* pLightShape)
  489. {
  490. _shapeQuadtree.add(pLightShape);
  491. }
  492. void LightSystem::removeShape(LightShape* pLightShape)
  493. {
  494. pLightShape->quadtreeRemove();
  495. }
  496. void LightSystem::addLight(const std::shared_ptr<LightPointEmission> &pointEmissionLight) {
  497. _lightPointEmissionQuadtree.add(pointEmissionLight.get());
  498. _pointEmissionLights.insert(pointEmissionLight);
  499. }
  500. void LightSystem::addLight(const std::shared_ptr<LightDirectionEmission> &directionEmissionLight) {
  501. _directionEmissionLights.insert(directionEmissionLight);
  502. }
  503. void LightSystem::removeLight(const std::shared_ptr<LightPointEmission> &pointEmissionLight) {
  504. std::unordered_set<std::shared_ptr<LightPointEmission>>::iterator it = _pointEmissionLights.find(pointEmissionLight);
  505. if (it != _pointEmissionLights.end()) {
  506. (*it)->quadtreeRemove();
  507. _pointEmissionLights.erase(it);
  508. }
  509. }
  510. void LightSystem::removeLight(const std::shared_ptr<LightDirectionEmission> &directionEmissionLight) {
  511. std::unordered_set<std::shared_ptr<LightDirectionEmission>>::iterator it = _directionEmissionLights.find(directionEmissionLight);
  512. if (it != _directionEmissionLights.end())
  513. _directionEmissionLights.erase(it);
  514. }
  515. //----- Normals -----//
  516. void LightSystem::normalsEnabled(bool enabled)
  517. {
  518. _normalsEnabled = enabled;
  519. }
  520. void LightSystem::normalsTargetSetView(sf::View view)
  521. {
  522. _normalsTexture.setView(view);
  523. }
  524. void LightSystem::normalsTargetClear()
  525. {
  526. _normalsTexture.clear(sf::Color{127u, 127u, 255u});
  527. }
  528. void LightSystem::normalsTargetDisplay()
  529. {
  530. _normalsTexture.display();
  531. }
  532. void LightSystem::normalsTargetDraw(const sf::Drawable& drawable, sf::RenderStates states)
  533. {
  534. _normalsTexture.draw(drawable, states);
  535. }